mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-11-16 14:13:46 +08:00
This commit is contained in:
106
web/src/views/asset/cash/columns.ts
Normal file
106
web/src/views/asset/cash/columns.ts
Normal 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,
|
||||
},
|
||||
];
|
||||
41
web/src/views/asset/cash/index.vue
Normal file
41
web/src/views/asset/cash/index.vue
Normal 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>
|
||||
415
web/src/views/asset/cash/list.vue
Normal file
415
web/src/views/asset/cash/list.vue
Normal 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>
|
||||
44
web/src/views/asset/creditsLog/index.vue
Normal file
44
web/src/views/asset/creditsLog/index.vue
Normal 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>
|
||||
93
web/src/views/asset/creditsLog/list.vue
Normal file
93
web/src/views/asset/creditsLog/list.vue
Normal 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>
|
||||
256
web/src/views/asset/creditsLog/model.ts
Normal file
256
web/src/views/asset/creditsLog/model.ts
Normal 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();
|
||||
101
web/src/views/asset/payRefund/index.vue
Normal file
101
web/src/views/asset/payRefund/index.vue
Normal 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>
|
||||
255
web/src/views/asset/payRefund/model.ts
Normal file
255
web/src/views/asset/payRefund/model.ts
Normal 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();
|
||||
287
web/src/views/asset/recharge/recharge.vue
Normal file
287
web/src/views/asset/recharge/recharge.vue
Normal 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>
|
||||
149
web/src/views/asset/rechargeLog/acceptRefund.vue
Normal file
149
web/src/views/asset/rechargeLog/acceptRefund.vue
Normal 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>
|
||||
132
web/src/views/asset/rechargeLog/applyRefund.vue
Normal file
132
web/src/views/asset/rechargeLog/applyRefund.vue
Normal 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>
|
||||
45
web/src/views/asset/rechargeLog/index.vue
Normal file
45
web/src/views/asset/rechargeLog/index.vue
Normal 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>
|
||||
228
web/src/views/asset/rechargeLog/list.vue
Normal file
228
web/src/views/asset/rechargeLog/list.vue
Normal 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>
|
||||
209
web/src/views/asset/rechargeLog/model.ts
Normal file
209
web/src/views/asset/rechargeLog/model.ts
Normal 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();
|
||||
Reference in New Issue
Block a user