feat: 自助充值

This commit is contained in:
tk
2025-06-27 19:19:35 +08:00
committed by nsnail
parent 94d0b7028f
commit e62153289f
83 changed files with 2112 additions and 110 deletions

View File

@ -21,6 +21,7 @@
"markdown-it": "14.1.0",
"markdown-it-emoji": "3.0.0",
"nprogress": "0.2.0",
"qrcode-svg": "1.1.0",
"sortablejs": "1.15.6",
"vkbeautify": "0.99.3",
"vue": "3.5.17",

View File

@ -0,0 +1,117 @@
/**
* 充值订单服务
* @module @/api/sys/deposit.order
*/
import config from '@/config'
import http from '@/utils/request'
export default {
/**
* 批量删除充值订单
*/
bulkDelete: {
url: `${config.API_URL}/api/sys/deposit.order/bulk.delete`,
name: `批量删除充值订单`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 充值订单计数
*/
count: {
url: `${config.API_URL}/api/sys/deposit.order/count`,
name: `充值订单计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 充值订单分组计数
*/
countBy: {
url: `${config.API_URL}/api/sys/deposit.order/count.by`,
name: `充值订单分组计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 创建充值订单
*/
create: {
url: `${config.API_URL}/api/sys/deposit.order/create`,
name: `创建充值订单`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 删除充值订单
*/
delete: {
url: `${config.API_URL}/api/sys/deposit.order/delete`,
name: `删除充值订单`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 编辑充值订单
*/
edit: {
url: `${config.API_URL}/api/sys/deposit.order/edit`,
name: `编辑充值订单`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 获取单个充值订单
*/
get: {
url: `${config.API_URL}/api/sys/deposit.order/get`,
name: `获取单个充值订单`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 获取充值配置
*/
getDepositConfig: {
url: `${config.API_URL}/api/sys/deposit.order/get.deposit.config`,
name: `获取充值配置`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 分页查询充值订单
*/
pagedQuery: {
url: `${config.API_URL}/api/sys/deposit.order/paged.query`,
name: `分页查询充值订单`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 支付确认
*/
payConfirm: {
url: `${config.API_URL}/api/sys/deposit.order/pay.confirm`,
name: `支付确认`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
}

View File

@ -188,7 +188,7 @@
<scContextmenuItem :title="$t('复制')" command="copy" divided icon="el-icon-copy-document" suffix="C"></scContextmenuItem>
<scContextmenuItem
v-if="contextOpers.includes('add')"
:title="$t('新')"
:title="$t('新')"
command="add"
divided
icon="el-icon-plus"

View File

@ -90,6 +90,8 @@ export default {
// Object.keys(item).forEach((x) => delete item[x])
// Object.assign(item, data)
// })
} else {
table.refresh()
}
},
}

View File

@ -99,9 +99,9 @@ export default {
性别: 'Gender',
成功: 'Successful',
我的消息: 'My messages',
属字典: 'Dictionary',
属角色: 'Role',
属部门: 'Department',
属字典: 'Dictionary',
属角色: 'Role',
属部门: 'Department',
手机号: 'Mobile',
手机号码: 'Mobile phone number',
手风琴菜单: 'Accordion menu',
@ -131,13 +131,13 @@ export default {
整页路由: 'Full page routing',
文化程度: 'Educational level',
斑马纹: 'Zebra pattern',
作业: 'Add job',
字典项: 'Add Dictionary Item',
消息: 'Add Message',
用户: 'Add User',
角色: 'Add Role',
部门: 'Add Department',
配置: 'Add Configuration',
作业: 'Add job',
字典项: 'Add Dictionary Item',
消息: 'Add Message',
用户: 'Add User',
角色: 'Add Role',
部门: 'Add Department',
配置: 'Add Configuration',
新密码: 'New password',
新手机号码: 'New mobile phone number',
新手机验证码: 'New mobile verification code',
@ -379,7 +379,7 @@ export default {
响应体: 'Response body',
响应头: 'Response header',
执行时间编号: 'Execution time ID',
字典目录: 'Add dictionary catalog',
字典目录: 'Add dictionary catalog',
字典名称: 'Dictionary name',
字典编码: 'Dictionary code',
父路径: 'Parent path',
@ -579,7 +579,7 @@ export default {
'结束值(毫秒)': 'End Value (ms)',
'起始值(毫秒)': 'Starting Value (ms)',
复制: 'Copy',
: 'New',
: 'New',
'数据已导出(上限 {n} 条)': 'Data exported (Maximum {n} entries)',
同步成功: 'Synchronization succeeded',
缓存详情: 'Cache details',
@ -587,11 +587,11 @@ export default {
数据权限: 'Data Permissions',
首页视图: 'Home view',
删除配置: 'Delete the configuration',
属字典目录: 'Dictionary catalog',
属字典目录: 'Dictionary catalog',
删除字典项: 'Delete dictionary entries',
接口总数: 'Total number of apis',
属文档分类: 'Document catalog',
请选择属文档分类: 'Please select the document category',
属文档分类: 'Document catalog',
请选择属文档分类: 'Please select the document category',
请输入文档标题: 'Please enter a title for the document',
请输入文档内容: 'Please enter the content of the document',
请选择档案可见性: 'Please select profile visibility',

View File

@ -99,9 +99,9 @@ export default {
性别: '性别',
成功: '成功',
我的消息: '我的消息',
属字典: '属字典',
属角色: '属角色',
属部门: '属部门',
属字典: '属字典',
属角色: '属角色',
属部门: '属部门',
手机号: '手机号',
手机号码: '手机号码',
手风琴菜单: '手风琴菜单',
@ -131,13 +131,13 @@ export default {
整页路由: '整页路由',
文化程度: '文化程度',
斑马纹: '斑马纹',
作业: '新作业',
字典项: '新字典项',
消息: '新消息',
用户: '新用户',
角色: '新角色',
部门: '新部门',
配置: '新配置',
作业: '新作业',
字典项: '新字典项',
消息: '新消息',
用户: '新用户',
角色: '新角色',
部门: '新部门',
配置: '新配置',
新密码: '新密码',
新手机号码: '新手机号码',
新手机验证码: '新手机验证码',
@ -378,7 +378,7 @@ export default {
响应体: '响应体',
响应头: '响应头',
执行时间编号: '执行时间编号',
字典目录: '新字典目录',
字典目录: '新字典目录',
字典名称: '字典名称',
字典编码: '字典编码',
父路径: '父路径',
@ -577,7 +577,7 @@ export default {
'结束值(毫秒)': '结束值(毫秒)',
'起始值(毫秒)': '起始值(毫秒)',
复制: '复制',
: '新',
: '新',
'数据已导出(上限 {n} 条)': '数据已导出(上限 {n} 条)',
同步成功: '同步成功',
缓存详情: '缓存详情',
@ -585,11 +585,11 @@ export default {
数据权限: '数据权限',
首页视图: '首页视图',
删除配置: '删除配置',
属字典目录: '属字典目录',
属字典目录: '属字典目录',
删除字典项: '删除字典项',
接口总数: '接口总数',
属文档分类: '属文档分类',
请选择属文档分类: '请选择属文档分类',
属文档分类: '属文档分类',
请选择属文档分类: '请选择属文档分类',
请输入文档标题: '请输入文档标题',
请输入文档内容: '请输入文档内容',
请选择档案可见性: '请选择档案可见性',

View File

@ -85,6 +85,11 @@
</template>
</el-table-column>
</el-table-column>
<el-table-column :label="$t('财务配置')" align="center">
<el-table-column :label="$t('人民币兑点数比率')" align="center" prop="cnyToPointRate" width="150" />
<el-table-column :label="$t('美元兑点数比率')" align="center" prop="usdToPointRate" width="150" />
<el-table-column :label="$t('USDT 收款地址')" align="center" prop="trc20ReceiptAddress" width="300" />
</el-table-column>
<el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="100">
<template #default="{ row }">
<el-switch v-model="row.enabled" @change="changeSwitch($event, row)"></el-switch>
@ -93,7 +98,7 @@
<naColOperation
:buttons="naColOperation.buttons.concat(naColOperation.delButton(this.$t('删除配置'), $API.sys_config.delete))"
:vue="this"
width="150" />
width="120" />
</scTable>
</el-main>
</el-container>

View File

@ -25,6 +25,19 @@
</el-form-item>
</div>
</el-collapse-item>
<el-collapse-item :title="$t('财务配置')" name="2">
<div style="margin: 1rem">
<el-form-item :label="$t('人民币兑点数比率')" prop="cnyToPointRate">
<el-input-number v-model="form.cnyToPointRate" :max="999999999" :min="1"></el-input-number>
</el-form-item>
<el-form-item :label="$t('美元兑点数比率')" prop="usdToPointRate">
<el-input-number v-model="form.usdToPointRate" :max="999999999" :min="1"></el-input-number>
</el-form-item>
<el-form-item :label="$t('USDT 收款地址')" prop="trc20ReceiptAddress">
<el-input v-model="form.trc20ReceiptAddress" maxlength="34" placeholder="placeholder"></el-input>
</el-form-item>
</div>
</el-collapse-item>
</el-collapse>
<el-form-item :label="$t('启用')" prop="enabled">
@ -70,7 +83,7 @@ export default {
userRegisterRoleId: [{ required: true, message: '请选择默认角色' }],
},
titleMap: {
add: this.$t('新配置'),
add: this.$t('新配置'),
edit: this.$t('编辑配置'),
view: this.$t('查看配置'),
},

View File

@ -81,7 +81,7 @@ export default {
},
tabId: '0',
titleMap: {
add: this.$t('新部门'),
add: this.$t('新部门'),
edit: this.$t('编辑部门'),
view: this.$t('查看部门'),
},

View File

@ -4,7 +4,7 @@
<el-tabs tab-position="top">
<el-tab-pane :label="$t('基本信息')">
<el-form :disabled="mode === 'view'" :model="form" :rules="rules" label-width="10rem" ref="dialogForm">
<el-form-item :label="$t('属字典目录')" prop="catalogId">
<el-form-item :label="$t('属字典目录')" prop="catalogId">
<catalog-select v-model="form.catalogId" class="w100p" />
</el-form-item>
<el-form-item :label="$t('项名')" prop="key">
@ -49,12 +49,12 @@ export default {
mode: 'add',
//验证规则
rules: {
catalogId: [{ required: true, message: '请选择属字典目录' }],
catalogId: [{ required: true, message: '请选择属字典目录' }],
key: [{ required: true, message: '请输入项名' }],
value: [{ required: true, message: '请输入项值' }],
},
titleMap: {
add: this.$t('新字典项'),
add: this.$t('新字典项'),
edit: this.$t('编辑字典项'),
view: this.$t('查看字典项'),
},

View File

@ -35,7 +35,7 @@ export default {
name: [{ required: true, message: '请输入字典目录名称' }],
},
titleMap: {
add: this.$t('新字典目录'),
add: this.$t('新字典目录'),
edit: this.$t('编辑字典目录'),
},
visible: false,

View File

@ -4,7 +4,7 @@
<el-tabs tab-position="top">
<el-tab-pane :label="$t('基本信息')">
<el-form :disabled="mode === 'view'" :model="form" :rules="rules" label-width="10rem" ref="dialogForm">
<el-form-item :label="$t('属文档分类')" prop="catalogId">
<el-form-item :label="$t('属文档分类')" prop="catalogId">
<catalog-select v-model="form.catalogId" class="w100p" />
</el-form-item>
<el-form-item :label="$t('文档标题')" prop="title">
@ -60,13 +60,13 @@ export default {
mode: 'add',
//验证规则
rules: {
catalogId: [{ required: true, message: this.$t('请选择属文档分类') }],
catalogId: [{ required: true, message: this.$t('请选择属文档分类') }],
title: [{ required: true, message: this.$t('请输入文档标题') }],
body: [{ required: true, message: this.$t('请输入文档内容') }],
visibility: [{ required: true, message: this.$t('请选择档案可见性') }],
},
titleMap: {
add: this.$t('新文档'),
add: this.$t('新文档'),
edit: this.$t('编辑文档'),
view: this.$t('查看文档'),
},

View File

@ -35,7 +35,7 @@ export default {
name: [{ required: true, message: '请输入文档分类名称' }],
},
titleMap: {
add: this.$t('新文档分类'),
add: this.$t('新文档分类'),
edit: this.$t('编辑文档分类'),
},
visible: false,

View File

@ -204,7 +204,7 @@ export default {
},
tabId: '0',
titleMap: {
add: this.$t('新作业'),
add: this.$t('新作业'),
edit: this.$t('编辑作业'),
view: this.$t('查看作业'),
},

View File

@ -133,7 +133,7 @@ export default {
//验证规则
rules: {},
titleMap: {
add: this.$t('新作业记录'),
add: this.$t('新作业记录'),
edit: this.$t('编辑作业记录'),
view: this.$t('查看作业记录'),
},

View File

@ -5,7 +5,7 @@
</el-col>
<template v-else>
<el-col>
<h2>{{ form.meta.title || '新菜单' }}</h2>
<h2>{{ form.meta.title || '新菜单' }}</h2>
<el-form :model="form" :rules="rules" label-width="15rem" ref="dialogForm">
<el-form-item :label="$t('显示名称')" prop="meta.title">
<el-input v-model="form.meta.title" :placeholder="$t('菜单显示名字')" clearable></el-input>

View File

@ -117,7 +117,7 @@ export default {
],
},
titleMap: {
add: this.$t('新消息'),
add: this.$t('新消息'),
edit: this.$t('编辑消息'),
view: this.$t('查看消息'),
},

View File

@ -0,0 +1,351 @@
<template>
<el-container>
<el-header v-loading="statistics.total === '...'" class="el-header-statistics">
<el-row :gutter="15">
<el-col :lg="24">
<el-card shadow="never">
<scStatistic :title="$t('总数')" :value="statistics.total" group-separator></scStatistic>
</el-card>
</el-col>
</el-row>
</el-header>
<el-header class="el-header-select-filter">
<scSelectFilter
:data="[
{
title: $t('订单状态'),
key: 'depositOrderStatus',
options: [
{ label: '全部', value: '' },
...Object.entries(this.$GLOBAL.enums.depositOrderStatues).map((x) => {
return {
value: x[0],
label: x[1][1],
badge: this.statistics.depositOrderStatus?.find(
(y) => y.key.depositOrderStatus.toLowerCase() === x[0].toLowerCase(),
)?.value,
}
}),
],
},
{
title: $t('支付方式'),
key: 'paymentMode',
options: [
{ label: '全部', value: '' },
...Object.entries(this.$GLOBAL.enums.paymentModes).map((x) => {
return {
value: x[0],
label: x[1][1],
badge: this.statistics.paymentMode?.find((y) => y.key.paymentMode.toLowerCase() === x[0].toLowerCase())?.value,
}
}),
],
},
]"
:label-width="15"
@on-change="filterChange"
ref="selectFilter"></scSelectFilter>
</el-header>
<el-header>
<div class="left-panel">
<na-search
:controls="[
{
type: 'select-input',
field: [
'dy',
[
{ label: $t('订单编号'), key: 'id' },
{ label: $t('用户名'), key: 'owner.userName' },
{ label: $t('用户编号'), key: 'ownerId' },
{ label: $t('充值点数'), key: 'depositPoint' },
],
],
placeholder: $t('匹配内容'),
style: 'width:25rem',
selectStyle: 'width:8rem',
},
]"
:vue="this"
@reset="onReset"
@search="onSearch"
dateFormat="YYYY-MM-DD HH:mm:ss"
dateType="datetimerange"
dateValueFormat="YYYY-MM-DD HH:mm:ss"
ref="search" />
</div>
<div class="right-panel">
<el-button @click="this.dialog.save = { mode: 'add' }" icon="el-icon-plus" type="primary"></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
:context-menus="[
'id',
'ownerId',
'createdTime',
'paymentMode',
'amount',
'depositPoint',
'toPointRate',
'owner.userName',
'depositOrderStatus',
'actualPayAmount',
]"
:context-multi="{ id: ['createdTime'], ownerId: ['owner.userName'] }"
:context-opers="['view']"
:default-sort="{ prop: 'id', order: 'descending' }"
:export-api="$API.sys_depositorder.export"
:params="query"
:query-api="$API.sys_depositorder.pagedQuery"
:vue="this"
@data-change="getStatistics"
@selection-change="
(items) => {
selection = items
}
"
ref="table"
remote-filter
remote-sort
row-key="id"
stripe>
<naColId :label="$t('订单编号')" prop="id" sortable="custom" width="170" />
<naColUser
:clickOpenDialog="$GLOBAL.hasApiPermission('api/sys/user/get')"
:label="$t('归属用户')"
header-align="center"
nestProp="owner.userName"
nestProp2="ownerId"
prop="ownerId"
sortable="custom"
width="170"></naColUser>
<naColIndicator
:label="$t('订单状态')"
:options="
Object.entries(this.$GLOBAL.enums.depositOrderStatues).map((x) => {
return { value: x[0], text: `${x[1][1]}`, type: x[1][2], pulse: x[1][3] === 'true' }
})
"
align="center"
prop="depositOrderStatus"
sortable="custom" />
<el-table-column
:formatter="(row) => $TOOL.groupSeparator(row.depositPoint)"
:label="$t('充值点数')"
align="right"
prop="depositPoint"
sortable="custom" />
<el-table-column
:formatter="(row) => $TOOL.groupSeparator(row.toPointRate)"
:label="$t('兑换比率')"
align="right"
prop="toPointRate"
sortable="custom" />
<el-table-column
:formatter="(row) => $TOOL.groupSeparator(row.actualPayAmount / 1000)"
:label="$t('支付金额')"
align="right"
prop="actualPayAmount"
sortable="custom" />
<naColIndicator
:label="$t('支付方式')"
:options="
Object.entries(this.$GLOBAL.enums.paymentModes).map((x) => {
return { value: x[0], text: `${x[1][1]}`, type: x[1][2], pulse: x[1][3] === 'true' }
})
"
align="center"
prop="paymentMode"
sortable="custom" />
<naColOperation
:buttons="[
naColOperation.buttons[0],
{
icon: 'el-icon-credit-card',
title: '支付',
click: async (row, vue) => {
vue.dialog.save = { row, mode: 'pay' }
},
condition: (row) => {
return row.depositOrderStatus === 'waitingForPayment'
},
},
]"
:vue="this"
width="120" />
</scTable>
</el-main>
</el-container>
<save-dialog
v-if="dialog.save"
@closed="dialog.save = null"
@mounted="$refs.saveDialog.open(dialog.save)"
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
ref="saveDialog"></save-dialog>
</template>
<script>
import { defineAsyncComponent } from 'vue'
import table from '@/config/table'
import naColOperation from '@/config/naColOperation'
const naColUser = defineAsyncComponent(() => import('@/components/naColUser'))
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
export default {
components: {
naColUser,
saveDialog,
},
computed: {
naColOperation() {
return naColOperation
},
table() {
return table
},
},
async created() {
if (this.ownerId) {
this.query.dynamicFilter.filters.push({ field: 'ownerId', operator: 'eq', value: this.ownerId })
}
},
data() {
return {
statistics: {
total: '...',
},
dialog: {},
loading: false,
query: {
dynamicFilter: {
filters: [],
},
filter: {},
keywords: this.keywords,
},
selection: [],
}
},
inject: ['reload'],
methods: {
filterChange(data) {
Object.entries(data).forEach(([key, value]) => {
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
})
this.$refs.search.search()
},
async getStatistics() {
this.statistics.total = this.$refs.table?.total
const res = await Promise.all([
this.$API.sys_depositorder.countBy.post({
dynamicFilter: {
filters: this.query.dynamicFilter.filters,
},
requiredFields: ['PaymentMode'],
}),
this.$API.sys_depositorder.countBy.post({
dynamicFilter: {
filters: this.query.dynamicFilter.filters,
},
requiredFields: ['DepositOrderStatus'],
}),
])
this.statistics.paymentMode = res[0].data
this.statistics.depositOrderStatus = res[1].data
},
//重置
onReset() {
Object.entries(this.$refs.selectFilter.selected).forEach(([key, _]) => (this.$refs.selectFilter.selected[key] = ['']))
if (this.ownerId) {
this.$refs.search.selectInputKey = 'ownerId'
}
},
//搜索
async onSearch(form) {
if (Array.isArray(form.dy.createdTime)) {
this.query.dynamicFilter.filters.push({
field: 'createdTime',
operator: 'dateRange',
value: form.dy.createdTime.map((x) => x.replace(/ 00:00:00$/, '')),
})
}
if (typeof form.dy['owner.userName'] === 'string' && form.dy['owner.userName'].trim() !== '') {
this.query.dynamicFilter.filters.push({
field: 'owner.userName',
operator: 'eq',
value: form.dy['owner.userName'],
})
}
if (typeof form.dy['ownerId'] === 'string' && form.dy['ownerId'].trim() !== '') {
this.query.dynamicFilter.filters.push({
field: 'ownerId',
operator: 'eq',
value: form.dy['ownerId'],
})
}
if (typeof form.dy['id'] === 'string' && form.dy['id'].trim() !== '') {
this.query.dynamicFilter.filters.push({
field: 'id',
operator: 'eq',
value: form.dy['id'],
})
}
if (typeof form.dy['paymentMode'] === 'string' && form.dy['paymentMode'].trim() !== '') {
this.query.dynamicFilter.filters.push({
field: 'paymentMode',
operator: 'eq',
value: form.dy['paymentMode'],
})
}
if (typeof form.dy['depositOrderStatus'] === 'string' && form.dy['depositOrderStatus'].trim() !== '') {
this.query.dynamicFilter.filters.push({
field: 'depositOrderStatus',
operator: 'eq',
value: form.dy['depositOrderStatus'],
})
}
if (typeof form.dy['depositPoint'] === 'string' && form.dy['depositPoint'].trim() !== '') {
this.query.dynamicFilter.filters.push({
field: 'depositPoint',
operator: 'eq',
value: form.dy['depositPoint'],
})
}
await this.$refs.table.upData()
},
},
async mounted() {
if (this.ownerId) {
this.$refs.search.selectInputKey = 'ownerId'
this.$refs.search.form.dy.ownerId = this.ownerId
this.$refs.search.keeps.push({
field: 'ownerId',
value: this.ownerId,
type: 'dy',
})
}
if (this.keywords) {
this.$refs.search.form.root.keywords = this.keywords
this.$refs.search.keeps.push({
field: 'keywords',
value: this.keywords,
type: 'root',
})
}
this.onReset()
},
props: ['keywords', 'ownerId'],
watch: {},
}
</script>
<style scoped></style>

View File

@ -0,0 +1,197 @@
<template>
<scDialog v-model="visible" :title="`${titleMap[mode]}${form?.id ?? '...'}`" @closed="$emit('closed')" destroy-on-close>
<div v-loading="loading">
<el-tabs v-model="tabId" @tab-change="tabChange" tab-position="top">
<el-tab-pane :label="$t('基本信息')" name="basic">
<el-form :disabled="mode === 'view' || mode === 'pay'" :model="form" :rules="rules" label-width="15rem" ref="dialogForm">
<el-form-item v-if="mode !== 'add'" :label="$t('订单编号')" prop="id">
<el-input v-model="form.id" clearable />
</el-form-item>
<el-form-item v-if="mode !== 'add'" :label="$t('订单状态')" prop="depositOrderStatus">
<el-select v-model="form.depositOrderStatus" filterable>
<el-option v-for="(item, i) in $GLOBAL.enums.depositOrderStatues" :key="i" :label="item[1]" :value="i" />
</el-select>
</el-form-item>
<el-form-item :label="$t('充值点数')" prop="depositPoint">
<el-input-number
:max="999999999"
:min="100"
:model-value="form.depositPoint"
:step="100"
@input="
(e) => {
if (e < 0) e = 0
if (e % 10 === 0) {
e += Math.floor(Math.random() * 9) + 1
}
if (e < 100) {
e += 100
}
this.form.depositPoint = e
}
"
clearable
style="width: 15rem" />
</el-form-item>
<el-form-item :label="$t('支付方式')" prop="paymentMode">
<el-select v-model="form.paymentMode" filterable>
<el-option v-for="(item, i) in $GLOBAL.enums.paymentModes" :key="i" :label="item[1]" :value="i" />
</el-select>
</el-form-item>
<el-form-item :label="$t('货币兑点数比率')" prop="toPointRate">
<el-input :model-value="form.toPointRate ? `1:${form.toPointRate}` : ''" disabled />
</el-form-item>
<el-form-item :label="$t('支付货币金额')" prop="actualPayAmount">
<el-input :model-value="form.actualPayAmount ? form.actualPayAmount / 1000 : ''" disabled />
</el-form-item>
<el-form-item v-if="mode === 'pay'" :label="$t('收款账号')" prop="receiptAccount">
<el-input v-model="form.receiptAccount" clearable />
</el-form-item>
<el-form-item v-if="mode === 'pay'" :label="$t('收款二维码')">
<div v-html="form.receiptAccountQrCode"></div>
</el-form-item>
<el-form-item v-if="mode !== 'add'" :label="$t('创建时间')" prop="createdTime">
<el-input v-model="form.createdTime" clearable />
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
<JsonViewer
:expand-depth="5"
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'dark' : 'light'"
:value="form"
copyable
expanded
sort></JsonViewer>
</el-tab-pane>
</el-tabs>
</div>
<template #footer>
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
<el-button v-if="mode === 'add'" :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('提交订单') }}</el-button>
<el-button
v-if="mode === 'pay'"
:disabled="loading"
:loading="loading"
@click="
async () => {
this.loading = true
try {
const res = await this.$API.sys_depositorder.payConfirm.post(this.form)
this.$emit('success', res.data, this.mode)
this.visible = false
this.$message.success(this.$t('操作成功'))
} catch {}
this.loading = false
}
"
type="danger"
>{{ $t('确认已支付') }}</el-button
>
</template>
</scDialog>
</template>
<script>
import QRCode from 'qrcode-svg'
export default {
computed: {},
components: {},
watch: {
'form.paymentMode': {
immediate: true,
handler(n, o) {
if (n === 'alipay' || n === 'weChat') {
this.form.toPointRate = this.config?.cnyToPointRate
} else if (n === 'usdt') {
this.form.toPointRate = this.config?.usdToPointRate
} else {
delete this.form.toPointRate
}
if (this.form.toPointRate && this.form.depositPoint) {
this.form.actualPayAmount = (this.form.depositPoint / this.form.toPointRate).toFixed(3) * 1000
} else {
delete this.form.actualPayAmount
}
},
},
'form.depositPoint': {
immediate: true,
handler(n, o) {
if (this.form.toPointRate) {
this.form.actualPayAmount = (n / this.form.toPointRate).toFixed(3) * 1000
}
},
},
},
data() {
return {
config: null,
//表单数据
form: {},
loading: true,
mode: 'add',
//验证规则
rules: {
depositPoint: [{ required: true, message: this.$t('请输入充值点数') }],
paymentMode: [{ required: true, message: this.$t('请选择支付方式') }],
},
tabId: 'basic',
titleMap: {
add: this.$t('新建充值订单'),
view: this.$t('查看充值订单'),
pay: this.$t('支付充值订单'),
},
visible: false,
}
},
emits: ['success', 'closed', 'mounted'],
methods: {
//显示
async open(data) {
this.visible = true
this.config = (await this.$API.sys_depositorder.getDepositConfig.post({})).data
if (data.mode === 'add') {
this.loading = false
return this
}
this.loading = true
this.mode = data.mode
if (data.row?.id) {
const res = await this.$API.sys_depositorder.get.post({ id: data.row.id })
if (res.data) {
Object.assign(this.form, res.data)
this.form.receiptAccountQrCode = new QRCode(this.form.receiptAccount).svg()
this.loading = false
return this
}
}
this.$message.error(`未找到该数据`)
return this
},
//表单提交方法
async submit() {
const valid = await this.$refs.dialogForm.validate().catch(() => {})
if (!valid) {
return false
}
this.loading = true
try {
const res = await this.$API.sys_depositorder.create.post(this.form)
this.$emit('success', res.data, this.mode)
this.visible = false
this.$message.success(this.$t('操作成功'))
} catch {}
this.loading = false
},
},
mounted() {
this.$emit('mounted')
},
}
</script>
<style scoped></style>

View File

@ -134,7 +134,7 @@ export default {
},
tabId: '0',
titleMap: {
add: this.$t('新角色'),
add: this.$t('新角色'),
edit: this.$t('编辑角色'),
view: this.$t('查看角色'),
},

View File

@ -109,7 +109,7 @@
<naColId :label="$t('交易编号')" prop="id" sortable="custom" width="170" />
<naColUser
:clickOpenDialog="$GLOBAL.hasApiPermission('api/sys/user/get')"
:label="$t('属用户')"
:label="$t('属用户')"
header-align="center"
nestProp="owner.userName"
nestProp2="ownerId"

View File

@ -22,16 +22,16 @@
<el-form-item :label="$t('交易后余额')">
<el-input :value="form.balanceBefore + form.amount" clearable />
</el-form-item>
<el-form-item :label="$t('所有者部门编号')" prop="ownerDeptId">
<el-form-item :label="$t('归属部门编号')" prop="ownerDeptId">
<el-input v-model="form.ownerDeptId" clearable />
</el-form-item>
<el-form-item :label="$t('所有者用户编号')" prop="ownerId">
<el-form-item :label="$t('归属用户编号')" prop="ownerId">
<el-input v-model="form.ownerId" clearable />
</el-form-item>
<el-form-item :label="$t('创建者用户编号')" prop="createdUserId">
<el-input v-model="form.createdUserId" clearable />
</el-form-item>
<el-form-item :label="$t('所有者用户名')" prop="createdUserName">
<el-form-item :label="$t('归属用户名')" prop="createdUserName">
<el-input v-model="form.createdUserName" clearable />
</el-form-item>
<el-form-item :label="$t('创建时间')" prop="createdTime">
@ -70,7 +70,7 @@ export default {
rules: {},
tabId: 'basic',
titleMap: {
add: this.$t('新交易'),
add: this.$t('新交易'),
edit: this.$t('编辑交易'),
view: this.$t('查看交易'),
},

View File

@ -41,7 +41,7 @@
field: ['filter', 'roleId'],
api: $API.sys_role.query,
config: { props: { label: 'name', value: 'id' } },
placeholder: $t('属角色'),
placeholder: $t('属角色'),
style: 'width:15rem',
},
]"
@ -121,13 +121,13 @@
</template>
</el-table-column>
<naColTags
:label="$t('属部门')"
:label="$t('属部门')"
@click="(item) => (this.dialog.deptSave = { row: item, mode: 'view' })"
field="name"
prop="dept"
width="120" />
<naColTags
:label="$t('属角色')"
:label="$t('属角色')"
@click="(item) => (this.dialog.roleSave = { row: item, mode: 'view' })"
field="name"
min-width="200"

View File

@ -50,7 +50,7 @@
</div>
</el-form-item>
<el-form-item :label="$t('属角色')" prop="roleIds">
<el-form-item :label="$t('属角色')" prop="roleIds">
<scSelect
v-if="!this.loading"
v-model="form.roleIds"
@ -61,7 +61,7 @@
filterable
multiple />
</el-form-item>
<el-form-item :label="$t('属部门')" prop="deptId">
<el-form-item :label="$t('属部门')" prop="deptId">
<naDept v-model="form.deptId" class="w100p"></naDept>
</el-form-item>
@ -315,18 +315,18 @@ export default {
pattern: this.$GLOBAL.chars.RGX_PASSWORD,
},
],
deptId: [{ required: true, message: '请选择属部门' }],
deptId: [{ required: true, message: '请选择属部门' }],
roleIds: [
{
required: true,
message: '请选择属角色',
message: '请选择属角色',
trigger: 'change',
},
],
},
tabId: '0',
titleMap: {
add: this.$t('新用户'),
add: this.$t('新用户'),
edit: this.$t('编辑用户'),
view: this.$t('查看用户'),
},

View File

@ -33,7 +33,7 @@
field: ['filter', 'deptId'],
api: $API.sys_dept.query,
config: { props: { label: 'name', value: 'id' } },
placeholder: $t('属部门'),
placeholder: $t('属部门'),
style: 'width:15rem',
condition: () => $GLOBAL.hasApiPermission('api/sys/dept/query'),
},
@ -42,7 +42,7 @@
field: ['filter', 'roleId'],
api: $API.sys_role.query,
config: { props: { label: 'name', value: 'id' } },
placeholder: $t('属角色'),
placeholder: $t('属角色'),
style: 'width:15rem',
condition: () => $GLOBAL.hasApiPermission('api/sys/dept/query'),
},
@ -92,7 +92,7 @@
<naColId :label="$t('钱包编号')" prop="id" sortable="custom" width="170" />
<naColUser
:clickOpenDialog="$GLOBAL.hasApiPermission('api/sys/user/get')"
:label="$t('属用户')"
:label="$t('属用户')"
nestProp="owner.userName"
nestProp2="ownerId"
prop="ownerId"

View File

@ -22,10 +22,10 @@
<el-form-item :label="$t('总支出')" prop="totalExpenditure">
<el-input v-model="form.totalExpenditure" clearable />
</el-form-item>
<el-form-item :label="$t('所有者部门编号')" prop="ownerDeptId">
<el-form-item :label="$t('归属部门编号')" prop="ownerDeptId">
<el-input v-model="form.ownerDeptId" clearable />
</el-form-item>
<el-form-item :label="$t('所有者用户编号')" prop="ownerId">
<el-form-item :label="$t('归属用户编号')" prop="ownerId">
<el-input v-model="form.ownerId" clearable />
</el-form-item>
<el-form-item :label="$t('创建时间')" prop="createdTime">
@ -75,7 +75,7 @@ export default {
rules: {},
tabId: 'basic',
titleMap: {
add: this.$t('新钱包'),
add: this.$t('新钱包'),
edit: this.$t('编辑钱包'),
view: this.$t('查看钱包'),
},

View File

@ -48,7 +48,7 @@ export default {
},
tabId: '0',
titleMap: {
add: this.$t('新用户'),
add: this.$t('新用户'),
edit: this.$t('编辑用户'),
view: this.$t('查看用户'),
},