This commit is contained in:
孟帅
2023-05-10 23:54:50 +08:00
parent bbe655a4d8
commit 49a96750bf
314 changed files with 15138 additions and 6244 deletions

View File

@@ -0,0 +1,106 @@
import { h } from 'vue';
import { NTag } from 'naive-ui';
const msgMap = {
1: '处理中',
2: '提现成功',
3: ' 提现异常',
};
export const statusOptions = [
{
value: 1,
label: '处理中',
},
{
value: 2,
label: '提现成功',
},
{
value: 3,
label: '提现异常',
},
];
export const columns = [
{
title: '提现ID',
key: 'id',
width: 100,
},
{
title: '用户名',
key: 'memberUser',
render(row) {
return row.memberUser;
},
width: 100,
},
{
title: '姓名',
key: 'memberName',
render(row) {
return row.memberName;
},
width: 100,
},
{
title: '提现金额',
key: 'money',
render(row) {
return row.money.toFixed(2);
},
width: 100,
},
{
title: '手续费',
key: 'fee',
render(row) {
return row.fee.toFixed(2);
},
width: 100,
},
{
title: '最终到账',
key: 'lastMoney',
render(row) {
return row.lastMoney.toFixed(2);
},
width: 100,
},
{
title: '处理结果',
key: 'msg',
render(row) {
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: row.status == 1 ? 'info' : row.status == 2 ? 'success' : 'warning',
bordered: false,
},
{
default: () => (row.msg == '' ? msgMap[row.status] : row.msg),
}
);
},
width: 200,
},
{
title: '申请IP',
key: 'ip',
width: 180,
},
{
title: '处理时间',
key: 'handleAt',
width: 180,
},
{
title: '申请时间',
key: 'createdAt',
width: 180,
},
];

View File

@@ -0,0 +1,41 @@
<template>
<div>
<div class="n-layout-page-header">
<n-card :bordered="false" title="提现管理" />
</div>
<n-card :bordered="false" class="proCard">
<n-tabs
type="card"
class="card-tabs"
:value="defaultTab"
animated
@before-leave="handleBeforeLeave"
>
<n-tab-pane name="" tab="全部"> <List :type="defaultTab" /></n-tab-pane>
<n-tab-pane name="1" tab="处理中"> <List :type="defaultTab" /> </n-tab-pane>
<n-tab-pane name="2" tab="提现成功"> <List :type="defaultTab" /> </n-tab-pane>
<n-tab-pane name="3" tab="提现异常"> <List :type="defaultTab" /> </n-tab-pane>
</n-tabs>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import List from './list.vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const defaultTab = ref('');
onMounted(() => {
if (router.currentRoute.value.query?.type) {
defaultTab.value = router.currentRoute.value.query.type as string;
}
});
function handleBeforeLeave(tabName: string) {
defaultTab.value = tabName;
}
</script>

View File

@@ -0,0 +1,415 @@
<template>
<div>
<n-card :bordered="false" class="proCard">
<BasicForm
@register="register"
@submit="handleSubmit"
@reset="handleReset"
@keyup.enter="handleSubmit"
ref="searchFormRef"
>
<template #statusSlot="{ model, field }">
<n-input v-model:value="model[field]" />
</template>
</BasicForm>
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="actionRef"
:actionColumn="actionColumn"
:scroll-x="1800"
>
<template #tableTitle>
<n-button type="primary" @click="addTable" class="min-left-space">
<template #icon>
<n-icon>
<MoneyCollectOutlined />
</n-icon>
</template>
申请提现
</n-button>
<n-button type="default" @click="setCash" class="min-left-space">
<template #icon>
<n-icon>
<EditOutlined />
</n-icon>
</template>
设置提现账户
</n-button>
</template>
</BasicTable>
<n-modal
v-model:show="showModal"
:show-icon="false"
preset="dialog"
title="申请提现"
:style="{
width: dialogWidth,
}"
>
<n-alert type="info">
<div v-html="config.cashTips"></div>
</n-alert>
<n-form
:model="formParams"
:rules="rules"
ref="formRef"
label-placement="left"
:label-width="100"
class="py-4"
>
<n-form-item label="可提现金额">
<n-input v-model:value="newUserInfo.balance" disabled />
<template #feedback
><p>{{ estimated }}</p></template
>
</n-form-item>
<br />
<n-form-item label="提现金额" path="money">
<n-input-number v-model:value="formParams.money" :min="1" :max="newUserInfo.balance">
<template #minus-icon>
<n-icon :component="ArrowDownCircleOutline" />
</template>
<template #add-icon>
<n-icon :component="ArrowUpCircleOutline" />
</template>
</n-input-number>
</n-form-item>
</n-form>
<template #action>
<n-space>
<n-button @click="() => (showModal = false)">取消</n-button>
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">确定</n-button>
</n-space>
</template>
</n-modal>
<n-modal
v-model:show="showPaymentModal"
:show-icon="false"
preset="dialog"
title="处理打款"
:style="{
width: dialogWidth,
}"
>
<n-form
:model="paymentParams"
:rules="rules"
ref="PaymentRef"
label-placement="left"
:label-width="100"
class="py-4"
>
<n-form-item label="最终到账金额">
<n-input v-model:value="paymentParams.lastMoney" disabled />
</n-form-item>
<n-form-item label="收款信息">
<n-input v-model:value="paymentParams.accountInfo" disabled />
</n-form-item>
<n-form-item label="收款码">
<n-carousel draggable>
<img style="width: 200px" class="carousel-img" :src="paymentParams.payeeCode" />
</n-carousel>
</n-form-item>
<n-form-item label="提现状态" path="status">
<n-radio-group v-model:value="paymentParams.status" name="status">
<n-radio-button
v-for="status in statusOptions"
:key="status.value"
:value="status.value"
:label="status.label"
/>
</n-radio-group>
</n-form-item>
<n-form-item label="处理结果">
<n-input v-model:value="paymentParams.msg" />
<template #feedback>不填默认显示提现状态</template>
</n-form-item>
</n-form>
<template #action>
<n-space>
<n-button @click="() => (showPaymentModal = false)">取消</n-button>
<n-button type="info" :loading="PaymentBtnLoading" @click="confirmPayment"
>确定</n-button
>
</n-space>
</template>
</n-modal>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { h, reactive, ref } from 'vue';
import { useMessage } from 'naive-ui';
import { BasicTable, TableAction } from '@/components/Table';
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
import { Apply, List, Payment, View } from '@/api/cash';
import { columns, statusOptions } from './columns';
import { ArrowDownCircleOutline, ArrowUpCircleOutline } from '@vicons/ionicons5';
import { MoneyCollectOutlined, EditOutlined } from '@vicons/antd';
import { defRangeShortcuts, timestampToTime } from '@/utils/dateUtil';
import { useRouter } from 'vue-router';
import { getUserInfo } from '@/api/system/user';
import { getCashConfig } from '@/api/sys/config';
interface Props {
type?: string;
}
const props = withDefaults(defineProps<Props>(), {
type: '',
});
const router = useRouter();
const params = ref<any>({
pageSize: 10,
title: '',
content: '',
status: null,
});
const rules = {};
const estimated = ref(
'本次提现预计将在 ' +
timestampToTime(new Date().setTime(new Date().getTime() + 86400 * 4 * 1000) / 1000) +
' 前到账 (1-3个工作日双休日和法定节假日顺延)'
);
const schemas: FormSchema[] = [
{
field: 'memberId',
component: 'NInput',
label: '管理员ID',
componentProps: {
placeholder: '请输入管理员ID',
onUpdateValue: (e: any) => {
console.log(e);
},
},
rules: [{ message: '请输入管理员ID', trigger: ['blur'] }],
},
{
field: 'ip',
component: 'NInput',
label: '申请IP',
componentProps: {
placeholder: '请输入申请IP',
onUpdateValue: (e: any) => {
console.log(e);
},
},
rules: [{ message: '请输入申请IP', trigger: ['blur'] }],
},
{
field: 'created_at',
component: 'NDatePicker',
label: '申请时间',
componentProps: {
type: 'datetimerange',
clearable: true,
shortcuts: defRangeShortcuts(),
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
];
const newUserInfo = ref({ balance: 0 });
const message = useMessage();
const actionRef = ref();
const showModal = ref(false);
const showPaymentModal = ref(false);
const PaymentRef = ref<any>({});
const PaymentBtnLoading = ref(false);
const formBtnLoading = ref(false);
const searchFormRef = ref<any>({});
const formRef = ref<any>({});
const config = ref<any>({
cashMinFee: 3,
cashMinFeeRatio: '0.03',
cashMinMoney: 0,
cashSwitch: false,
cashTips: '',
});
const resetFormParams = {
money: null,
accountInfo: null,
};
let formParams = ref<any>(resetFormParams);
const resetPaymentParams = {
id: null,
money: null,
};
let paymentParams = ref<any>(resetPaymentParams);
const actionColumn = reactive({
auth: ['/cash/payment'],
width: 100,
title: '操作',
key: 'action',
fixed: 'right',
render(record) {
return h(TableAction as any, {
style: 'button',
actions: [
{
label: '处理打款',
onClick: handleEdit.bind(null, record),
},
],
});
},
});
function setCash() {
router.push({
name: 'home_account',
query: {
type: 3,
},
});
}
const [register, {}] = useForm({
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
labelWidth: 80,
schemas,
});
async function addTable() {
showModal.value = true;
formParams.value = resetFormParams;
newUserInfo.value = await getUserInfo();
if (newUserInfo.value.balance < config.value.cashMinMoney) {
message.error('当前余额不满足提现条件,至少需要:' + config.value.cashMinMoney + '元');
}
}
const loadDataTable = async (res) => {
mapWidth();
config.value = await getCashConfig();
config.value = config.value.list;
return await List({
...params.value,
...res,
...searchFormRef.value.formModel,
...{ status: props.type },
});
};
function reloadTable() {
actionRef.value.reload();
}
/**
* 申请提现
* @param e
*/
function confirmForm(e) {
e.preventDefault();
formBtnLoading.value = true;
formRef.value.validate((errors) => {
if (!errors) {
Apply({ money: formParams.value.money })
.then((_res) => {
message.success('操作成功');
setTimeout(() => {
showModal.value = false;
reloadTable();
formParams.value = ref(resetFormParams);
});
})
.catch((_e: Error) => {
// message.error(e.message ?? '操作失败');
});
} else {
message.error('请填写完整信息');
}
formBtnLoading.value = false;
});
}
/**
* 处理打款
* @param e
*/
function confirmPayment(e) {
e.preventDefault();
PaymentBtnLoading.value = true;
PaymentRef.value.validate((errors) => {
if (!errors) {
Payment({
id: PaymentRef.value.model.id,
status: PaymentRef.value.model.status,
msg: PaymentRef.value.model.msg,
})
.then((_res) => {
message.success('操作成功');
setTimeout(() => {
showPaymentModal.value = false;
reloadTable();
PaymentRef.value = ref(resetPaymentParams);
});
})
.catch((_e: Error) => {
// message.error(e.message ?? '操作失败');
});
} else {
message.error('请填写完整信息');
}
PaymentBtnLoading.value = false;
});
}
async function handleEdit(record: Recordable) {
showPaymentModal.value = true;
paymentParams.value = record;
paymentParams.value = await View({ id: record.id });
paymentParams.value.lastMoney = paymentParams.value.lastMoney.toFixed(2);
paymentParams.value.accountInfo =
paymentParams.value.name + ' - ' + paymentParams.value.account;
}
function handleSubmit(values: Recordable) {
console.log(values);
params.value = values;
reloadTable();
}
function handleReset(values: Recordable) {
params.value = values;
reloadTable();
}
const dialogWidth = ref('50%');
function mapWidth() {
let val = document.body.clientWidth;
const def = 720; // 默认宽度
if (val < def) {
dialogWidth.value = '100%';
} else {
dialogWidth.value = def + 'px';
}
return dialogWidth.value;
}
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,44 @@
<template>
<div>
<div class="n-layout-page-header">
<n-card :bordered="false" title="资金变动">
你和下级在平台中余额积分的变动明细都可以在这里进行查看
</n-card>
</div>
<n-card :bordered="false" class="proCard">
<n-tabs
type="card"
class="card-tabs"
:value="defaultTab"
animated
@before-leave="handleBeforeLeave"
>
<n-tab-pane name="" tab="全部"> <List :type="defaultTab" /></n-tab-pane>
<n-tab-pane name="balance" tab="余额明细"> <List :type="defaultTab" /> </n-tab-pane>
<n-tab-pane name="integral" tab="积分明细"> <List :type="defaultTab" /> </n-tab-pane>
</n-tabs>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import List from './list.vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const defaultTab = ref('');
onMounted(() => {
if (router.currentRoute.value.query?.type) {
defaultTab.value = router.currentRoute.value.query.type as string;
}
});
function handleBeforeLeave(tabName: string) {
defaultTab.value = tabName;
}
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,93 @@
<template>
<div>
<n-card :bordered="false" class="proCard">
<BasicForm
@register="register"
@submit="reloadTable"
@reset="reloadTable"
@keyup.enter="reloadTable"
ref="searchFormRef"
>
<template #statusSlot="{ model, field }">
<n-input v-model:value="model[field]" />
</template>
</BasicForm>
<BasicTable
:openChecked="false"
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="actionRef"
:scroll-x="1800"
:resizeHeightOffset="-10000"
size="small"
>
<template #tableTitle>
<n-button
type="primary"
@click="handleExport"
class="min-left-space"
v-if="hasPermission(['/creditsLog/export'])"
>
<template #icon>
<n-icon>
<ExportOutlined />
</n-icon>
</template>
导出
</n-button>
</template>
</BasicTable>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { useMessage } from 'naive-ui';
import { BasicTable } from '@/components/Table';
import { BasicForm, useForm } from '@/components/Form/index';
import { usePermission } from '@/hooks/web/usePermission';
import { List, Export } from '@/api/creditsLog';
import { columns, schemas } from './model';
import { ExportOutlined } from '@vicons/antd';
interface Props {
type?: string;
}
const props = withDefaults(defineProps<Props>(), {
type: '',
});
const { hasPermission } = usePermission();
const actionRef = ref();
const message = useMessage();
const searchFormRef = ref<any>({});
const [register, {}] = useForm({
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
labelWidth: 80,
schemas,
});
const loadDataTable = async (res) => {
return await List({
...searchFormRef.value?.formModel,
...res,
...{ creditType: props.type },
});
};
function reloadTable() {
actionRef.value.reload();
}
function handleExport() {
message.loading('正在导出列表...', { duration: 1200 });
Export(searchFormRef.value?.formModel);
}
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,256 @@
import { h, ref } from 'vue';
import { NTag } from 'naive-ui';
import { cloneDeep } from 'lodash-es';
import { FormSchema } from '@/components/Form';
import { Option } from '@/api/creditsLog';
import { isNullObject } from '@/utils/is';
import { defRangeShortcuts } from '@/utils/dateUtil';
import { getOptionLabel, getOptionTag, Options } from '@/utils/hotgo';
export interface State {
id: number;
memberId: number;
appId: string;
addonsName: string;
creditType: string;
creditGroup: string;
beforeNum: number;
num: number;
afterNum: number;
remark: string;
ip: string;
mapId: number;
status: number;
createdAt: string;
updatedAt: string;
}
export const defaultState = {
id: 0,
memberId: 0,
appId: '',
addonsName: '',
creditType: '',
creditGroup: '',
beforeNum: 0,
num: 0,
afterNum: 0,
remark: '',
ip: '',
mapId: 0,
status: 1,
createdAt: '',
updatedAt: '',
};
export function newState(state: State | null): State {
if (state !== null) {
return cloneDeep(state);
}
return cloneDeep(defaultState);
}
export const options = ref<Options>({
creditType: [],
creditGroup: [],
});
export const rules = {};
export const schemas = ref<FormSchema[]>([
{
field: 'memberId',
component: 'NInput',
label: '管理员ID',
componentProps: {
placeholder: '请输入管理员ID',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'creditGroup',
component: 'NSelect',
label: '组别',
defaultValue: null,
componentProps: {
placeholder: '请选择变动的组别',
options: [],
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'remark',
component: 'NInput',
label: '备注',
componentProps: {
placeholder: '请输入备注',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'ip',
component: 'NInput',
label: '操作人IP',
componentProps: {
placeholder: '请输入操作人IP',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'createdAt',
component: 'NDatePicker',
label: '变动时间',
componentProps: {
type: 'datetimerange',
clearable: true,
shortcuts: defRangeShortcuts(),
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'id',
component: 'NInput',
label: '变动ID',
componentProps: {
placeholder: '请输入变动ID',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
]);
export const columns = [
{
title: '变动ID',
key: 'id',
width: 100,
},
{
title: '管理员ID',
key: 'memberId',
width: 100,
},
{
title: '变动类型',
key: 'creditType',
render(row) {
if (isNullObject(row.creditType)) {
return ``;
}
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: getOptionTag(options.value.creditType, row.creditType),
bordered: false,
},
{
default: () => getOptionLabel(options.value.creditType, row.creditType),
}
);
},
width: 150,
},
{
title: '组别',
key: 'creditGroup',
render(row) {
if (isNullObject(row.creditGroup)) {
return ``;
}
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: getOptionTag(options.value.creditGroup, row.creditGroup),
bordered: false,
},
{
default: () => getOptionLabel(options.value.creditGroup, row.creditGroup),
}
);
},
width: 150,
},
{
title: '变动前',
key: 'beforeNum',
width: 100,
render(row) {
return Number(row.beforeNum).toFixed(2);
},
},
{
title: '变动数量',
key: 'num',
width: 100,
render(row) {
return Number(row.num).toFixed(2);
},
},
{
title: '变动后',
key: 'afterNum',
width: 100,
render(row) {
return Number(row.afterNum).toFixed(2);
},
},
{
title: '备注',
key: 'remark',
width: 200,
},
{
title: '操作人IP',
key: 'ip',
width: 150,
},
{
title: '关联ID',
key: 'mapId',
width: 100,
render(row) {
if (row.mapId === 0) {
return '-';
}
return row.mapId;
},
},
{
title: '变动时间',
key: 'createdAt',
width: 180,
},
];
async function loadOptions() {
options.value = await Option();
for (const item of schemas.value) {
switch (item.field) {
case 'creditType':
item.componentProps.options = options.value.creditType;
break;
case 'creditGroup':
item.componentProps.options = options.value.creditGroup;
break;
}
}
}
await loadOptions();

View File

@@ -0,0 +1,101 @@
<template>
<div>
<n-card :bordered="false" class="proCard">
<div class="n-layout-page-header">
<n-card :bordered="false" title="交易退款">
<!-- 这是系统自动生成的CURD表格你可以将此行注释改为表格的描述 -->
</n-card>
</div>
<BasicForm
@register="register"
@submit="reloadTable"
@reset="reloadTable"
@keyup.enter="reloadTable"
ref="searchFormRef"
>
<template #statusSlot="{ model, field }">
<n-input v-model:value="model[field]" />
</template>
</BasicForm>
<BasicTable
:openChecked="false"
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="actionRef"
:actionColumn="actionColumn"
@update:checked-row-keys="onCheckedRow"
:scroll-x="1090"
:resizeHeightOffset="-10000"
size="small"
>
<template #tableTitle>
<n-button
type="primary"
@click="handleExport"
class="min-left-space"
v-if="hasPermission(['/creditsLog/export'])"
>
<template #icon>
<n-icon>
<ExportOutlined />
</n-icon>
</template>
导出
</n-button>
</template>
</BasicTable>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { h, reactive, ref } from 'vue';
import { useMessage } from 'naive-ui';
import { BasicTable, TableAction } from '@/components/Table';
import { BasicForm, useForm } from '@/components/Form/index';
import { usePermission } from '@/hooks/web/usePermission';
import { List, Export } from '@/api/pay/refund';
import { columns, schemas } from './model';
import { ExportOutlined } from '@vicons/antd';
const { hasPermission } = usePermission();
const actionRef = ref();
const message = useMessage();
const searchFormRef = ref<any>({});
const actionColumn = reactive({
width: 300,
title: '操作',
key: 'action',
// fixed: 'right',
render(record) {
return h(TableAction as any, {
style: 'button',
actions: [],
});
},
});
const [register, {}] = useForm({
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
labelWidth: 80,
schemas,
});
const loadDataTable = async (res) => {
return await List({ ...searchFormRef.value?.formModel, ...res });
};
function reloadTable() {
actionRef.value.reload();
}
function handleExport() {
message.loading('正在导出列表...', { duration: 1200 });
Export(searchFormRef.value?.formModel);
}
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,255 @@
import { h, ref } from 'vue';
import { NAvatar, NImage, NTag, NSwitch, NRate } from 'naive-ui';
import { cloneDeep } from 'lodash-es';
import { FormSchema } from '@/components/Form';
import { Dicts } from '@/api/dict/dict';
import { isNullObject } from '@/utils/is';
import { defRangeShortcuts } from '@/utils/dateUtil';
import { getOptionLabel, getOptionTag, Options } from '@/utils/hotgo';
export interface State {
id: number;
memberId: number;
appId: string;
addonsName: string;
creditType: string;
creditGroup: string;
beforeNum: number;
num: number;
afterNum: number;
remark: string;
ip: string;
mapId: number;
status: number;
createdAt: string;
updatedAt: string;
}
export const defaultState = {
id: 0,
memberId: 0,
appId: '',
addonsName: '',
creditType: '',
creditGroup: '',
beforeNum: 0,
num: 0,
afterNum: 0,
remark: '',
ip: '',
mapId: 0,
status: 1,
createdAt: '',
updatedAt: '',
};
export function newState(state: State | null): State {
if (state !== null) {
return cloneDeep(state);
}
return cloneDeep(defaultState);
}
export const options = ref<Options>({
sys_normal_disable: [],
});
export const rules = {};
export const schemas = ref<FormSchema[]>([
{
field: 'id',
component: 'NInputNumber',
label: '变动ID',
componentProps: {
placeholder: '请输入变动ID',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'memberId',
component: 'NInputNumber',
label: '管理员ID',
componentProps: {
placeholder: '请输入管理员ID',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'appId',
component: 'NInput',
label: '应用id',
componentProps: {
placeholder: '请输入应用id',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'creditType',
component: 'NSelect',
label: '变动类型',
defaultValue: null,
componentProps: {
placeholder: '请选择变动类型',
options: [],
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'creditGroup',
component: 'NSelect',
label: '变动的组别',
defaultValue: null,
componentProps: {
placeholder: '请选择变动的组别',
options: [],
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'remark',
component: 'NInput',
label: '备注',
componentProps: {
placeholder: '请输入备注',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'ip',
component: 'NInput',
label: '操作人IP',
componentProps: {
placeholder: '请输入操作人IP',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'status',
component: 'NSelect',
label: '状态',
defaultValue: null,
componentProps: {
placeholder: '请选择状态',
options: [],
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'createdAt',
component: 'NDatePicker',
label: '创建时间',
componentProps: {
type: 'datetimerange',
clearable: true,
shortcuts: defRangeShortcuts(),
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
]);
export const columns = [
{
title: '变动ID',
key: 'id',
},
{
title: '管理员ID',
key: 'memberId',
},
{
title: '应用id',
key: 'appId',
},
{
title: '插件名称',
key: 'addonsName',
},
{
title: '变动前',
key: 'beforeNum',
},
{
title: '变动数据',
key: 'num',
},
{
title: '变动后',
key: 'afterNum',
},
{
title: '备注',
key: 'remark',
},
{
title: '操作人IP',
key: 'ip',
},
{
title: '关联ID',
key: 'mapId',
},
{
title: '状态',
key: 'status',
render(row) {
if (isNullObject(row.status)) {
return ``;
}
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: getOptionTag(options.value.sys_normal_disable, row.status),
bordered: false,
},
{
default: () => getOptionLabel(options.value.sys_normal_disable, row.status),
}
);
},
},
{
title: '创建时间',
key: 'createdAt',
},
{
title: '修改时间',
key: 'updatedAt',
},
];
async function loadOptions() {
options.value = await Dicts({
types: ['sys_normal_disable'],
});
for (const item of schemas.value) {
switch (item.field) {
case 'status':
item.componentProps.options = options.value.sys_normal_disable;
break;
}
}
}
await loadOptions();

View File

@@ -0,0 +1,287 @@
<template>
<div>
<div class="n-layout-page-header">
<n-card :bordered="false" title="在线充值"> 余额可用于购买付费产品或商城消费 </n-card>
</div>
<n-spin :show="loading">
<n-grid class="mt-6" cols="1 s:1 m:1 l:4 xl:4 2xl:4" responsive="screen" :x-gap="12">
<n-gi span="4">
<n-card :bordered="false" class="proCard">
<n-thing>
<template #description> <span class="title">充值金额</span> </template>
<n-space>
<n-button
type="primary"
ghost
v-for="item in amounts"
:key="item"
@click="SetAmount(item)"
>
{{ item }}
<n-icon
class="check-icon"
:size="18"
:component="CheckOutlined"
v-if="amount === item && amountType === 1"
/>
</n-button>
<n-input-number v-model:value="amount" v-if="amountType === 2">
<template #prefix> </template>
</n-input-number>
</n-space>
<template #footer> <span class="title">支付方式 </span></template>
<template #action>
<n-space>
<n-button
strong
secondary
:color="item.color"
v-for="item in payTypes"
:key="item"
@click="SetPayType(item.value)"
>
<template #icon>
<n-icon :component="item.icon" />
</template>
{{ item.label }}
<n-icon
class="check-icon"
:size="18"
:component="CheckOutlined"
v-if="payType === item.value"
/>
</n-button>
</n-space>
<n-button
type="success"
class="create-order-button"
size="large"
@click="CreateOrder"
>
立即充值
</n-button>
</template>
</n-thing>
</n-card>
</n-gi>
</n-grid>
</n-spin>
<n-modal v-model:show="showQrModal" :show-icon="false" preset="dialog" :title="qrParams.name">
<n-form class="py-4">
<div class="text-center">
<qrcode-vue :value="qrParams.qrUrl" :size="220" class="canvas" style="margin: 0 auto" />
</div>
</n-form>
<template #action>
<n-space>
<n-button @click="() => (showQrModal = false)">关闭</n-button>
</n-space>
</template>
</n-modal>
<RechargeLog class="mt-6" />
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, inject } from 'vue';
import wx from 'weixin-js-sdk';
import { WechatOutlined, AlipayOutlined, QqOutlined, CheckOutlined } from '@vicons/antd';
import { useMessage } from 'naive-ui';
import { Create } from '@/api/order';
import QrcodeVue from 'qrcode.vue';
import RechargeLog from '../rechargeLog/index.vue';
import { SocketEnum } from '@/enums/socketEnum';
import { addOnMessage } from '@/utils/websocket';
const showQrModal = ref(false);
const qrParams = ref({
name: '',
qrUrl: '',
});
const loading = ref(false);
const message = useMessage();
const amountType = ref(1);
const amounts = ref([0.01, 10, 20, 30, 50, 100, '其他金额']);
const payTypes = ref([
{ value: 'wxpay', label: '微信支付', icon: WechatOutlined, color: '#18a058' },
{ value: 'alipay', label: '支付宝', icon: AlipayOutlined, color: '#2d8cf0' },
{ value: 'qqpay', label: 'QQ支付', icon: QqOutlined, color: '#2d8cf0' },
]);
const amount = ref<any>(null);
const payType = ref<any>(null);
onMounted(() => {});
function SetPayType(type: string) {
payType.value = type;
}
function SetAmount(a: number | string) {
amount.value = a;
if (a === '其他金额') {
amountType.value = 2;
amount.value = null;
} else {
amountType.value = 1;
}
}
function CreateOrder() {
if (amount.value === null || amount.value <= 0) {
message.error('请选择充值金额');
return;
}
if (payType.value === null || payType.value === '') {
message.error('请选择支付方式');
return;
}
loading.value = true;
Create({
orderType: 'balance',
payType: payType.value,
money: amount.value,
returnUrl: window.location.href,
})
.then((res) => {
if (res.order?.tradeType === undefined || res.order?.tradeType === '') {
message.error('创建支付订单失败,没找到交易方式,请联系管理处理!');
return;
}
if (res.order?.tradeType !== 'mp') {
if (res.order?.payURL === undefined || res.order?.payURL === '') {
message.error('创建支付订单失败,没找到支付地址,请联系管理处理!');
return;
}
}
switch (res.order?.tradeType) {
case 'scan':
showQr(res.order?.payURL, '打开微信【扫一扫】完成支付');
break;
case 'mp':
if (res.order.jsApi === undefined) {
message.error('支付失败请选择其他支付方式JSAPI支付参数无效');
return;
}
const jsApi = res.order.jsApi;
// 配置微信JS SDK
wx.config({
// debug: true,
appId: jsApi.config.app_id,
timestamp: jsApi.config.timestamp,
nonceStr: jsApi.config.nonce_str,
signature: jsApi.config.signature,
jsApiList: ['chooseWXPay'],
});
// 配置完成后返回一个resolve
wx.ready(() => {
wxJSPay({
timestamp: jsApi.params.timeStamp,
nonceStr: jsApi.params.nonceStr,
package: jsApi.params.package,
signType: jsApi.params.signType,
paySign: jsApi.params.paySign,
})
.then((_res) => {
// ...
})
.catch((err) => {
message.success('支付失败:', err.message);
});
});
break;
case 'qqweb':
showQr(res.order?.payURL, '打开QQ【扫一扫】完成支付');
break;
default:
window.open(res.order?.payURL, '_blank');
}
})
.finally(() => {
loading.value = false;
});
}
// 发起微信公众号支付
function wxJSPay(params) {
return new Promise((resolve, reject) => {
// 调用微信支付
wx.chooseWXPay({
timestamp: params.timestamp,
nonceStr: params.nonceStr,
package: params.package,
signType: params.signType,
paySign: params.paySign,
success: (res) => {
// 支付成功时返回resolve
resolve(res);
},
fail: (err) => {
// 支付失败时返回reject
reject(err);
},
});
});
}
function showQr(url: string, name: string) {
qrParams.value.qrUrl = url;
qrParams.value.name = name;
showQrModal.value = true;
}
const onMessageList = inject('onMessageList');
const handleMessageList = (res) => {
const data = JSON.parse(res.data);
if (data.event === SocketEnum.EventAdminOrderNotify) {
if (data.code == SocketEnum.CodeErr) {
message.error('查询出错:' + data.event);
return;
}
showQrModal.value = false;
message.success('支付成功');
location.reload();
return;
}
};
addOnMessage(onMessageList, handleMessageList);
</script>
<style lang="less" scoped>
::v-deep(.n-thing .n-thing-main .n-thing-main__footer:not(:first-child)) {
margin-top: 36px;
margin-bottom: 10px;
}
::v-deep(.title) {
font-weight: var(--n-title-font-weight);
transition: color 0.3s var(--n-bezier);
flex: 1;
min-width: 0;
color: var(--n-title-text-color);
font-size: 18px;
}
::v-deep(.check-icon) {
margin-left: 3px;
}
::v-deep(.create-order-button) {
margin-top: 28px;
}
</style>

View File

@@ -0,0 +1,149 @@
<template>
<div>
<n-spin :show="loading" description="请稍候...">
<n-modal
v-model:show="isShowModal"
:show-icon="false"
preset="dialog"
title="受理退款申请"
:style="{
width: dialogWidth,
}"
>
<n-form
:model="params"
:rules="rules"
ref="formRef"
label-placement="left"
:label-width="80"
class="py-4"
>
<n-form-item label="业务单号" path="orderSn">
<n-input v-model:value="params.orderSn" :disabled="true" />
</n-form-item>
<n-form-item label="订单金额" path="money">
<n-input placeholder="请输入标题" v-model:value="params.money" :disabled="true" />
</n-form-item>
<n-form-item label="退款原因" path="refundReason">
<n-input
type="textarea"
placeholder="请填写退款原因"
v-model:value="params.refundReason"
:disabled="true"
/>
</n-form-item>
<n-form-item label="更新状态" path="status">
<n-select v-model:value="params.status" :options="options.acceptRefundStatus" />
</n-form-item>
<n-form-item label="拒绝原因" path="rejectRefundReason" v-if="params.status === 9">
<n-input
type="textarea"
placeholder="请填拒绝退款原因"
v-model:value="params.rejectRefundReason"
/>
</n-form-item>
<n-form-item label="退款备注" path="remark" v-if="params.status === 8">
<n-input type="textarea" placeholder="请填退款备注" v-model:value="params.remark" />
</n-form-item>
</n-form>
<template #action>
<n-space>
<n-button @click="closeForm">取消</n-button>
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">确定</n-button>
</n-space>
</template>
</n-modal>
</n-spin>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, computed, watch } from 'vue';
import { rules, State, newState, options } from './model';
import { useMessage } from 'naive-ui';
import { adaModalWidth } from '@/utils/hotgo';
import { AcceptRefund, View } from '@/api/order';
const emit = defineEmits(['reloadTable', 'updateShowModal']);
interface Props {
showModal: boolean;
formParams?: State;
}
const props = withDefaults(defineProps<Props>(), {
showModal: false,
formParams: () => {
return newState(null);
},
});
const isShowModal = computed({
get: () => {
return props.showModal;
},
set: (value) => {
emit('updateShowModal', value);
},
});
const loading = ref(false);
const params = ref<State>(props.formParams);
const message = useMessage();
const formRef = ref<any>({});
const dialogWidth = ref('75%');
const formBtnLoading = ref(false);
function confirmForm(e) {
e.preventDefault();
formBtnLoading.value = true;
formRef.value.validate((errors) => {
if (!errors) {
AcceptRefund(params.value).then((_res) => {
message.success('操作成功');
setTimeout(() => {
isShowModal.value = false;
emit('reloadTable');
});
});
} else {
message.error('请填写完整信息');
}
formBtnLoading.value = false;
});
}
onMounted(async () => {
adaModalWidth(dialogWidth);
});
function closeForm() {
isShowModal.value = false;
}
function loadForm(value) {
loading.value = true;
// 编辑
View({ id: value.id })
.then((res) => {
params.value = res;
})
.finally(() => {
loading.value = false;
});
}
watch(
() => props.formParams,
(value) => {
loadForm(value);
}
);
</script>
<style lang="less"></style>

View File

@@ -0,0 +1,132 @@
<template>
<div>
<n-spin :show="loading" description="请稍候...">
<n-modal
v-model:show="isShowModal"
:show-icon="false"
preset="dialog"
title="退款申请"
:style="{
width: dialogWidth,
}"
>
<n-form
:model="params"
:rules="rules"
ref="formRef"
label-placement="left"
:label-width="80"
class="py-4"
>
<n-form-item label="业务单号" path="orderSn">
<n-input v-model:value="params.orderSn" :disabled="true" />
</n-form-item>
<n-form-item label="订单金额" path="money">
<n-input placeholder="请输入标题" v-model:value="params.money" :disabled="true" />
</n-form-item>
<n-form-item label="退款原因" path="refundReason">
<n-input
type="textarea"
placeholder="请填写退款原因"
v-model:value="params.refundReason"
/>
</n-form-item>
</n-form>
<template #action>
<n-space>
<n-button @click="closeForm">取消</n-button>
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">确定</n-button>
</n-space>
</template>
</n-modal>
</n-spin>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, computed, watch } from 'vue';
import { rules, State, newState } from './model';
import { useMessage } from 'naive-ui';
import { adaModalWidth } from '@/utils/hotgo';
import { ApplyRefund, View } from '@/api/order';
const emit = defineEmits(['reloadTable', 'updateShowModal']);
interface Props {
showModal: boolean;
formParams?: State;
}
const props = withDefaults(defineProps<Props>(), {
showModal: false,
formParams: () => {
return newState(null);
},
});
const isShowModal = computed({
get: () => {
return props.showModal;
},
set: (value) => {
emit('updateShowModal', value);
},
});
const loading = ref(false);
const params = ref<State>(props.formParams);
const message = useMessage();
const formRef = ref<any>({});
const dialogWidth = ref('75%');
const formBtnLoading = ref(false);
function confirmForm(e) {
e.preventDefault();
formBtnLoading.value = true;
formRef.value.validate((errors) => {
if (!errors) {
ApplyRefund(params.value).then((_res) => {
message.success('操作成功');
setTimeout(() => {
isShowModal.value = false;
emit('reloadTable');
});
});
} else {
message.error('请填写完整信息');
}
formBtnLoading.value = false;
});
}
onMounted(async () => {
adaModalWidth(dialogWidth);
});
function closeForm() {
isShowModal.value = false;
}
function loadForm(value) {
loading.value = true;
// 编辑
View({ id: value.id })
.then((res) => {
params.value = res;
})
.finally(() => {
loading.value = false;
});
}
watch(
() => props.formParams,
(value) => {
loadForm(value);
}
);
</script>
<style lang="less"></style>

View File

@@ -0,0 +1,45 @@
<template>
<div>
<div class="n-layout-page-header">
<n-card :bordered="false" title="充值记录" />
</div>
<n-card :bordered="false" class="proCard">
<n-tabs
type="card"
class="card-tabs"
:value="defaultTab"
animated
@before-leave="handleBeforeLeave"
>
<n-tab-pane
:name="item.key.toString()"
:tab="item.label"
v-for="item in options.status"
:key="item.key"
>
<List :type="defaultTab" />
</n-tab-pane>
</n-tabs>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import List from './list.vue';
import { useRouter } from 'vue-router';
import { options } from '@/views/asset/rechargeLog/model';
const router = useRouter();
const defaultTab = ref('-1');
onMounted(() => {
if (router.currentRoute.value.query?.type) {
defaultTab.value = router.currentRoute.value.query.type as string;
}
});
function handleBeforeLeave(tabName: string) {
defaultTab.value = tabName;
}
</script>

View File

@@ -0,0 +1,228 @@
<template>
<div>
<n-card :bordered="false" class="proCard">
<BasicForm
@register="register"
@submit="reloadTable"
@reset="reloadTable"
@keyup.enter="reloadTable"
ref="searchFormRef"
>
<template #statusSlot="{ model, field }">
<n-input v-model:value="model[field]" />
</template>
</BasicForm>
<BasicTable
:openChecked="true"
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="actionRef"
:actionColumn="actionColumn"
@update:checked-row-keys="onCheckedRow"
:scroll-x="1800"
:resizeHeightOffset="-10000"
>
<template #tableTitle>
<n-button
type="error"
@click="handleBatchDelete"
:disabled="batchDeleteDisabled"
class="min-left-space"
v-if="hasPermission(['/order/delete'])"
>
<template #icon>
<n-icon>
<DeleteOutlined />
</n-icon>
</template>
批量删除
</n-button>
<n-button
type="primary"
@click="handleExport"
class="min-left-space"
v-if="hasPermission(['/order/export'])"
>
<template #icon>
<n-icon>
<ExportOutlined />
</n-icon>
</template>
导出
</n-button>
</template>
</BasicTable>
</n-card>
<ApplyRefund
@reloadTable="reloadTable"
@updateShowModal="updateShowModal"
:showModal="showModal"
:formParams="formParams"
/>
<AcceptRefund
@reloadTable="reloadTable"
@updateShowModal="updateAcceptShowModal"
:showModal="showAcceptModal"
:formParams="formParams"
/>
</div>
</template>
<script lang="ts" setup>
import { h, reactive, ref } from 'vue';
import { useDialog, useMessage } from 'naive-ui';
import { BasicTable, TableAction } from '@/components/Table';
import { BasicForm, useForm } from '@/components/Form/index';
import { usePermission } from '@/hooks/web/usePermission';
import { List, Export, Delete } from '@/api/order';
import { State, columns, schemas, newState } from './model';
import { ExportOutlined, DeleteOutlined } from '@vicons/antd';
import ApplyRefund from './applyRefund.vue';
import AcceptRefund from './acceptRefund.vue';
interface Props {
type?: string;
}
const props = withDefaults(defineProps<Props>(), {
type: '-1',
});
const { hasPermission } = usePermission();
const actionRef = ref();
const dialog = useDialog();
const message = useMessage();
const searchFormRef = ref<any>({});
const batchDeleteDisabled = ref(true);
const checkedIds = ref([]);
const showModal = ref(false);
const showAcceptModal = ref(false);
const formParams = ref<State>();
const actionColumn = reactive({
width: 120,
title: '操作',
key: 'action',
fixed: 'right',
render(record) {
return h(TableAction as any, {
style: 'button',
actions: [
{
type: 'warning',
label: '受理退款',
onClick: handleAcceptRefund.bind(null, record),
auth: ['/order/acceptRefund'],
ifShow: () => {
return record.status == 6;
},
},
{
type: 'default',
label: '申请退款',
onClick: handleApplyRefund.bind(null, record),
auth: ['/order/applyRefund'],
ifShow: () => {
return record.status == 4;
},
},
{
label: '删除',
onClick: handleDelete.bind(null, record),
auth: ['/order/delete'],
ifShow: () => {
return record.status == 5;
},
},
],
});
},
});
const [register, {}] = useForm({
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
labelWidth: 80,
schemas,
});
const loadDataTable = async (res) => {
return await List({ ...searchFormRef.value?.formModel, ...res, ...{ status: props.type } });
};
function reloadTable() {
actionRef.value.reload();
}
function onCheckedRow(rowKeys) {
batchDeleteDisabled.value = rowKeys.length <= 0;
checkedIds.value = rowKeys;
}
function handleExport() {
message.loading('正在导出列表...', { duration: 1200 });
Export(searchFormRef.value?.formModel);
}
function handleDelete(record: Recordable) {
dialog.warning({
title: '警告',
content: '你确定要删除?',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
Delete(record).then((_res) => {
message.success('删除成功');
reloadTable();
});
},
onNegativeClick: () => {
// message.error('取消');
},
});
}
function handleBatchDelete() {
dialog.warning({
title: '警告',
content: '你确定要批量删除?只有已关闭的订单才能被删除',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
Delete({ id: checkedIds.value }).then((_res) => {
message.success('删除成功');
reloadTable();
});
},
onNegativeClick: () => {
// message.error('取消');
},
});
}
function updateShowModal(value) {
showModal.value = value;
}
function handleApplyRefund(record: Recordable) {
showModal.value = true;
formParams.value = newState(record as State);
}
function updateAcceptShowModal(value) {
showAcceptModal.value = value;
}
function handleAcceptRefund(record: Recordable) {
showAcceptModal.value = true;
formParams.value = newState(record as State);
}
defineExpose({
reloadTable,
});
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,209 @@
import { h, ref } from 'vue';
import { NTag } from 'naive-ui';
import { cloneDeep } from 'lodash-es';
import { FormSchema } from '@/components/Form';
import { Option } from '@/api/order';
import { isNullObject } from '@/utils/is';
import { defRangeShortcuts } from '@/utils/dateUtil';
import { getOptionLabel, getOptionTag, Options } from '@/utils/hotgo';
export interface State {
id: number;
memberId: number;
orderType: string;
productId: number;
orderSn: string;
money: number;
remark: string;
payLogOutTradeNo: string;
status: number;
createdAt: string;
updatedAt: string;
refundReason: string;
rejectRefundReason: string;
payLogPayType: string;
}
export const defaultState = {
id: 0,
memberId: 0,
orderType: '',
productId: 0,
orderSn: '',
money: 0,
payLogOutTradeNo: '',
remark: '',
status: 1,
createdAt: '',
updatedAt: '',
refundReason: '',
rejectRefundReason: '',
payLogPayType: '',
};
export function newState(state: State | null): State {
if (state !== null) {
return cloneDeep(state);
}
return cloneDeep(defaultState);
}
export const options = ref<Options>({
status: [],
acceptRefundStatus: [],
payType: [],
});
export const rules = {};
export const schemas = ref<FormSchema[]>([
{
field: 'memberId',
component: 'NInput',
label: '管理员ID',
componentProps: {
placeholder: '请输入管理员ID',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'orderSn',
component: 'NInput',
label: '业务单号',
componentProps: {
placeholder: '请输入业务订单号',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'payLogOutTradeNo',
component: 'NInput',
label: '商户单号',
componentProps: {
placeholder: '请输入商户订单号',
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'createdAt',
component: 'NDatePicker',
label: '创建时间',
componentProps: {
type: 'datetimerange',
clearable: true,
shortcuts: defRangeShortcuts(),
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
]);
export const columns = [
{
title: '订单ID',
key: 'id',
width: 100,
},
{
title: '管理员ID',
key: 'memberId',
width: 100,
},
{
title: '业务订单号',
key: 'orderSn',
width: 260,
},
{
title: '商户订单号',
key: 'payLogOutTradeNo',
width: 260,
},
{
title: '支付方式',
key: 'payLogPayType',
render(row) {
if (isNullObject(row.payLogPayType)) {
return ``;
}
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: getOptionTag(options.value.payType, row.payLogPayType),
bordered: false,
},
{
default: () => getOptionLabel(options.value.payType, row.payLogPayType),
}
);
},
width: 150,
},
{
title: '充值金额',
key: 'money',
width: 100,
render(row) {
return '¥' + Number(row.money).toFixed(2);
},
},
{
title: '订单状态',
key: 'status',
render(row) {
if (isNullObject(row.status)) {
return ``;
}
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: getOptionTag(options.value.status, row.status),
bordered: false,
},
{
default: () =>
getOptionLabel(options.value.status, row.status) +
(row.status === 9 ? '' + row.rejectRefundReason : ''),
}
);
},
width: 150,
},
{
title: '创建时间',
key: 'createdAt',
width: 180,
},
];
async function loadOptions() {
options.value = await Option();
for (const item of schemas.value) {
switch (item.field) {
case 'status':
item.componentProps.options = options.value.status;
break;
case 'acceptRefundStatus':
item.componentProps.options = options.value.acceptRefundStatus;
break;
case 'payType':
item.componentProps.options = options.value.payType;
break;
}
}
}
await loadOptions();