优化小程序菜单管理功能

This commit is contained in:
gxwebsoft
2024-06-01 02:45:33 +08:00
parent 4bae8599e1
commit e3fb9ba283
36 changed files with 2161 additions and 430 deletions

View File

@@ -18,24 +18,6 @@
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="选择场馆" name="merchantId" v-if="!getMerchantId()">
<SelectMerchantMultipleDown
:placeholder="`选择场馆`"
class="input-item"
v-model:value="form.merchantName"
@done="chooseMerchantId"
/>
</a-form-item>
<a-form-item label="选择角色" name="roles">
<role-select v-model:value="form.roles" />
<!-- <SelectRole-->
<!-- :placeholder="`选择角色`"-->
<!-- class="input-item"-->
<!-- :type="`merchant`"-->
<!-- v-model:value="form.roleName"-->
<!-- @done="chooseRoleId"-->
<!-- />-->
</a-form-item>
<a-form-item label="账号" name="username">
<a-input
allow-clear
@@ -68,6 +50,12 @@
v-model:value="form.realName"
/>
</a-form-item>
<a-form-item label="选择角色" name="roles">
<role-select v-model:value="form.roles" />
</a-form-item>
<a-form-item label="可管理场馆" name="merchantId">
<MerchantSelect v-model:value="merchants" />
</a-form-item>
</a-form>
</ele-modal>
</template>
@@ -83,9 +71,12 @@
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance, RuleObject } from 'ant-design-vue/es/form';
import RoleSelect from './role-select.vue';
import MerchantSelect from './merchant-select.vue';
import { getMerchantId } from '@/utils/common';
import { getMerchantName } from '@/utils/merchant';
import { useUserStore } from '@/store/modules/user';
import { Merchant } from '@/api/shop/merchant/model';
import { listMerchant } from '@/api/shop/merchant';
const userStore = useUserStore();
@@ -118,6 +109,7 @@
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
const isSuperAdmin = ref<boolean>(false);
const merchants = ref<Merchant[]>([]);
// 用户信息
const form = reactive<User>({
@@ -127,6 +119,7 @@
nickname: '',
realName: '',
companyName: '',
merchants: '',
merchantId: getMerchantId(),
merchantName: getMerchantName(),
sex: undefined,
@@ -162,14 +155,14 @@
trigger: 'blur'
}
],
merchantId: [
{
required: true,
type: 'number',
message: '请选择场馆',
trigger: 'blur'
}
],
// merchantId: [
// {
// required: true,
// type: 'string',
// message: '请选择场馆',
// trigger: 'blur'
// }
// ],
roles: [
{
required: true,
@@ -236,7 +229,8 @@
.then(() => {
loading.value = true;
const formData = {
...form
...form,
merchants: merchants.value?.map((d) => d.merchantId).join(',')
};
if (getMerchantId()) {
form.merchantId = getMerchantId();
@@ -263,8 +257,21 @@
(visible) => {
if (visible) {
images.value = [];
merchants.value = [];
if (props.data) {
assignObject(form, props.data);
if (props.data.merchants) {
listMerchant({ merchantIds: props.data.merchants }).then((list) => {
merchants.value = list;
});
}
// if (props.data.comments) {
// listMerchant({ merchantCodes: props.data.comments }).then(
// (list) => {
// merchants.value = list;
// }
// );
// }
isUpdate.value = true;
} else {
resetFields();

View File

@@ -0,0 +1,73 @@
<!-- 角色选择下拉框 -->
<template>
<a-select
allow-clear
mode="multiple"
:value="merchantIds"
:placeholder="placeholder"
@update:value="updateValue"
@blur="onBlur"
>
<a-select-option
v-for="item in data"
:key="item.merchantId"
:value="item.merchantId"
>
{{ item.merchantName }}
</a-select-option>
</a-select>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import { message } from 'ant-design-vue/es';
import { Merchant } from '@/api/shop/merchant/model';
import { listMerchant } from '@/api/shop/merchant';
const emit = defineEmits<{
(e: 'update:value', value: Merchant[]): void;
(e: 'blur'): void;
}>();
const props = withDefaults(
defineProps<{
// 选中的商户
value?: Merchant[];
//
placeholder?: string;
}>(),
{
placeholder: '请选择场馆'
}
);
// 选中的角色id
const merchantIds = computed(() =>
props.value?.map((d) => d.merchantId as number)
);
// 角色数据
const data = ref<Merchant[]>([]);
/* 更新选中数据 */
const updateValue = (value: number[]) => {
emit(
'update:value',
value.map((v) => ({ merchantId: v }))
);
};
/* 获取角色数据 */
listMerchant({})
.then((list) => {
data.value = list;
})
.catch((e) => {
message.error(e.message);
});
/* 失去焦点 */
const onBlur = () => {
emit('blur');
};
</script>

View File

@@ -7,13 +7,22 @@
</template>
<span>添加</span>
</a-button>
<a-input-search
allow-clear
placeholder="请输入关键词"
v-model:value="where.keywords"
@pressEnter="search"
@search="search"
/>
<a-button @click="reset">重置</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
import useSearch from '@/utils/use-search';
import { UserParam } from '@/api/system/user/model';
const props = withDefaults(
defineProps<{
@@ -24,7 +33,7 @@
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'search', where?: UserParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
@@ -35,6 +44,25 @@
emit('add');
};
// 表单数据
const { where, resetFields } = useSearch<UserParam>({
userId: undefined,
username: undefined,
phone: undefined,
realName: undefined,
keywords: undefined
});
const search = () => {
emit('search', where);
};
/* 重置 */
const reset = () => {
resetFields();
search();
};
watch(
() => props.selection,
() => {}

View File

@@ -38,7 +38,7 @@
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a-space v-if="record.username != 'admin'">
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
@@ -72,7 +72,7 @@
import Edit from './components/edit.vue';
import { pageUsers, removeUser, removeUsers } from '@/api/system/user';
import type { User, UserParam } from '@/api/system/user/model';
import { getMerchantId } from "@/utils/common";
import { getMerchantId } from '@/utils/common';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
@@ -106,14 +106,6 @@
...orders,
page,
limit
}).then((res) => {
res?.list.map((d) => {
d.roles = d.roles?.filter(
(m) => m.roleCode == 'merchant' || m.roleCode == 'merchantClerk'
);
return d;
});
return res;
});
};
@@ -126,12 +118,6 @@
align: 'center',
width: 90
},
{
title: '场馆名称',
dataIndex: 'merchantName',
key: 'merchantName',
align: 'center'
},
{
title: '账号',
dataIndex: 'username',
@@ -156,6 +142,12 @@
key: 'roles',
align: 'center'
},
// {
// title: '可管理场馆',
// dataIndex: 'merchantName',
// key: 'merchantName',
// align: 'center'
// },
{
title: '操作',
key: 'action',

View File

@@ -19,13 +19,16 @@
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="选择场馆" name="merchantName">
<SelectMerchant
:placeholder="`选择场馆`"
class="input-item"
v-model:value="form.merchantName"
@done="chooseMerchantId"
/>
<!-- <a-form-item label="选择场馆" name="merchantName">-->
<!-- <SelectMerchant-->
<!-- :placeholder="`选择场馆`"-->
<!-- class="input-item"-->
<!-- v-model:value="form.merchantName"-->
<!-- @done="chooseMerchantId"-->
<!-- />-->
<!-- </a-form-item>-->
<a-form-item label="适用场馆" name="merchants">
<MerchantSelect v-model:value="merchants" />
</a-form-item>
<a-form-item label="会员卡名称" name="cardName">
<a-input
@@ -34,10 +37,23 @@
v-model:value="form.cardName"
/>
</a-form-item>
<a-form-item label="会员卡类型" name="cardCode">
<a-form-item label="会员卡类型" name="type">
<a-select
v-model:value="form.type"
placeholder="会员卡类型"
:style="`width: 200px`"
>
<a-select-option :value="1">年卡</a-select-option>
<a-select-option :value="2">次卡</a-select-option>
<a-select-option :value="3">月卡</a-select-option>
<a-select-option :value="4">会员IC卡</a-select-option>
<a-select-option :value="5">充值卡</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="会员卡分组" name="cardCode">
<DictSelect
dict-code="cardPlanId"
:placeholder="`会员卡类型`"
:placeholder="`会员卡分组`"
style="width: 200px"
v-model:value="form.cardCode"
/>
@@ -79,12 +95,32 @@
v-model:value="form.discount"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
<a-form-item label="成人/儿童" name="cardType">
<a-select
allow-clear
v-model:value="form.cardType"
placeholder="成人/儿童"
:style="`width: 200px`"
>
<a-select-option :value="1">成人</a-select-option>
<a-select-option :value="2">儿童</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="卡片背景" name="image">
<SelectFile
:placeholder="`请选择图片`"
:limit="1"
:data="images"
@done="chooseImage"
@del="onDeleteItem"
/>
</a-form-item>
<a-form-item label="会员卡说明" name="content">
<!-- 编辑器 -->
<tinymce-editor
v-model:value="content"
:init="config"
placeholder="会员卡说明"
/>
</a-form-item>
<a-form-item label="状态" name="status">
@@ -115,9 +151,15 @@
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FormInstance, RuleObject } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
import { Merchant } from '@/api/shop/merchant/model';
import gfm from '@bytemd/plugin-gfm';
import zh_HansGfm from '@bytemd/plugin-gfm/locales/zh_Hans.json';
import highlight from '@bytemd/plugin-highlight';
import TinymceEditor from '@/components/TinymceEditor/index.vue';
import MerchantSelect from '@/views/booking/account/components/merchant-select.vue';
import { listMerchant } from '@/api/shop/merchant';
// 是否是修改
const isUpdate = ref(false);
@@ -145,12 +187,16 @@
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
const content = ref('');
const merchants = ref<Merchant[]>([]);
// 用户信息
const form = reactive<Card>({
cardId: undefined,
cardName: '',
cardCode: undefined,
type: undefined,
cardType: undefined,
image: '',
price: undefined,
number: 0,
@@ -172,6 +218,20 @@
// 表单验证规则
const rules = reactive({
merchants: [
{
required: true,
type: 'string',
message: '请选择可适用的场馆',
trigger: 'blur',
validator: async (_rule: RuleObject) => {
if (merchants.value.length == 0) {
return Promise.reject('请选择可适用的场馆');
}
return Promise.resolve();
}
}
],
merchantName: [
{
required: true,
@@ -188,11 +248,19 @@
trigger: 'blur'
}
],
type: [
{
required: true,
type: 'number',
message: '请选择会员卡类型',
trigger: 'blur'
}
],
cardCode: [
{
required: true,
type: 'string',
message: '请选择会员卡类型',
message: '请选择会员卡分组',
trigger: 'blur'
}
],
@@ -214,12 +282,17 @@
]
});
/* 搜索 */
const chooseMerchantId = (item: Merchant) => {
form.merchantName = item.merchantName;
form.merchantId = item.merchantId;
form.merchantType = item.shopType;
};
// 插件
const plugins = ref([
gfm({
locale: zh_HansGfm
}),
highlight()
]);
const config = ref({
height: 500
});
const chooseImage = (data: FileRecord) => {
images.value.push({
@@ -247,7 +320,9 @@
.then(() => {
loading.value = true;
const formData = {
...form
...form,
comments: content.value,
merchantIds: merchants.value?.map((d) => d.merchantId).join(',')
};
const saveOrUpdate = isUpdate.value ? updateCard : addCard;
saveOrUpdate(formData)
@@ -270,6 +345,7 @@
(visible) => {
if (visible) {
images.value = [];
merchants.value = [];
if (props.data) {
assignObject(form, props.data);
if (props.data.image) {
@@ -279,6 +355,16 @@
status: 'done'
});
}
if (props.data.merchantIds) {
listMerchant({ merchantIds: props.data.merchantIds }).then(
(list) => {
merchants.value = list;
}
);
}
if (props.data.comments) {
content.value = props.data.comments;
}
isUpdate.value = true;
} else {
isUpdate.value = false;

View File

@@ -7,11 +7,19 @@
</template>
<span>添加</span>
</a-button>
<a-radio-group v-model:value="where.cardCode" @change="handleSearch">
<a-radio-button :value="`月/年卡`">/年卡</a-radio-button>
<a-radio-button :value="`次卡`">次卡</a-radio-button>
<a-radio-button :value="`充值卡`">充值卡</a-radio-button>
</a-radio-group>
<DictSelect
dict-code="cardPlanId"
class="form-item"
placeholder="按会员卡分组"
style="width: 180px"
v-model:value="where.cardCode"
@change="handleSearch"
/>
<!-- <a-radio-group v-model:value="where.cardCode" @change="handleSearch">-->
<!-- <a-radio-button :value="`月/年卡`">/年卡</a-radio-button>-->
<!-- <a-radio-button :value="`次卡`">次卡</a-radio-button>-->
<!-- <a-radio-button :value="`充值卡`">充值卡</a-radio-button>-->
<!-- </a-radio-group>-->
</a-space>
</template>
@@ -43,7 +51,7 @@
// 表单数据
const { where } = useSearch<any>({
cardCode: '月/年卡'
cardCode: undefined
});
const handleSearch = () => {

View File

@@ -115,9 +115,11 @@
},
{
title: '会员卡类型',
dataIndex: 'cardCode',
key: 'cardCode',
align: 'center'
dataIndex: 'type',
key: 'type',
align: 'center',
customRender: ({ text }) =>
['', '年卡', '次卡', '月卡', '会员IC卡', '充值卡'][text]
},
{
title: '会员卡名称',

View File

@@ -214,6 +214,7 @@
orders,
filters
}) => {
console.log(props);
if (props.categoryId) {
where.merchantId = props.categoryId;
}

View File

@@ -1,19 +1,21 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
<a-input-search
allow-clear
placeholder="请输入关键词"
v-model:value="where.keywords"
@pressEnter="search"
@search="search"
/>
<a-button @click="reset">重置</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
import useSearch from '@/utils/use-search';
import { UserParam } from '@/api/system/user/model';
const props = withDefaults(
defineProps<{
@@ -24,7 +26,7 @@
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'search', where?: UserParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
@@ -35,6 +37,25 @@
emit('add');
};
// 表单数据
const { where, resetFields } = useSearch<UserParam>({
userId: undefined,
username: undefined,
phone: undefined,
realName: undefined,
keywords: undefined
});
const search = () => {
emit('search', where);
};
/* 重置 */
const reset = () => {
resetFields();
search();
};
watch(
() => props.selection,
() => {}

View File

@@ -7,7 +7,6 @@
row-key="integralId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
@@ -101,47 +100,40 @@
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '用户id',
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
width: 90
},
{
title: '微信昵称',
dataIndex: 'username',
key: 'username',
align: 'center',
align: 'center'
},
{
title: '手机号码',
dataIndex: 'phone',
key: 'phone',
align: 'center',
dataIndex: 'mobile',
key: 'mobile',
align: 'center'
},
{
title: '获得积分',
dataIndex: 'integral',
key: 'integral',
align: 'center',
align: 'center'
},
{
title: '日期',
dataIndex: 'dateTime',
key: 'dateTime',
align: 'center',
align: 'center'
},
{
title: '天',
dataIndex: 'day',
key: 'day',
align: 'center',
align: 'center'
},
{
title: '签到时间',
@@ -151,15 +143,15 @@
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
// {
// title: '操作',
// key: 'action',
// width: 180,
// fixed: 'right',
// align: 'center',
// hideInSetting: true
// }
]);
/* 搜索 */

View File

@@ -79,6 +79,7 @@
:labelStyle="{ width: '90px', color: '#808080' }"
>
<template v-if="form.payStatus == 1">
<a-tag v-if="form.payType == 0">余额支付</a-tag>
<a-tag v-if="form.payType == 1">微信支付</a-tag>
<a-tag v-if="form.payType == 2">积分</a-tag>
<a-tag v-if="form.payType == 3">支付宝</a-tag>

View File

@@ -1,12 +1,12 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<SelectMerchantDown
:placeholder="`选择场馆`"
class="input-item"
v-model:value="where.merchantCode"
@change="search"
/>
<!-- <SelectMerchantDown-->
<!-- :placeholder="`选择场馆`"-->
<!-- class="input-item"-->
<!-- v-model:value="where.merchantCode"-->
<!-- @change="search"-->
<!-- />-->
<a-input-search
allow-clear
v-model:value="where.keywords"
@@ -14,7 +14,7 @@
@search="search"
@pressEnter="search"
/>
<!-- <a-button @click="getCode">生成支付二维码</a-button>-->
<!-- <a-button @click="getCode">生成支付二维码</a-button>-->
<a-button @click="reset">重置</a-button>
</a-space>
<ele-modal

View File

@@ -27,6 +27,7 @@
</template>
<template v-if="column.key === 'payType'">
<template v-if="record.payStatus == 1">
<a-tag v-if="record.payType == 0">余额支付</a-tag>
<a-tag v-if="record.payType == 1"
><WechatOutlined class="tag-icon" />微信支付</a-tag
>

View File

@@ -59,6 +59,14 @@
@done="chooseShopType"
/>
</a-form-item>
<a-form-item label="项目类型" name="itemType">
<DictSelect
dict-code="ItemType"
:placeholder="`请选择项目类型`"
style="width: 120px"
v-model:value="form.itemType"
/>
</a-form-item>
<a-form-item label="营业时间" name="businessTime">
<!-- <a-time-picker-->
<!-- v-model:value="form.timePeriod1"-->
@@ -123,17 +131,17 @@
v-model:value="form.price"
/>
</a-form-item>
<!-- <a-form-item label="手续费(%)" name="commission">-->
<!-- <a-input-number-->
<!-- :step="1"-->
<!-- :max="100"-->
<!-- :min="0.0"-->
<!-- :precision="2"-->
<!-- class="ele-fluid"-->
<!-- placeholder="请输入手续费"-->
<!-- v-model:value="form.commission"-->
<!-- />-->
<!-- </a-form-item>-->
<!-- <a-form-item label="手续费(%)" name="commission">-->
<!-- <a-input-number-->
<!-- :step="1"-->
<!-- :max="100"-->
<!-- :min="0.0"-->
<!-- :precision="2"-->
<!-- class="ele-fluid"-->
<!-- placeholder="请输入手续费"-->
<!-- v-model:value="form.commission"-->
<!-- />-->
<!-- </a-form-item>-->
<a-form-item label="关键字" name="keywords">
<a-select
v-model:value="form.keywords"
@@ -280,6 +288,7 @@
phone: undefined,
realName: undefined,
shopType: undefined,
itemType: undefined,
category: undefined,
province: '',
city: '',

View File

@@ -140,6 +140,12 @@
key: 'phone',
align: 'center'
},
{
title: '项目类型',
dataIndex: 'itemType',
key: 'itemType',
align: 'center'
},
{
title: '类型',
dataIndex: 'shopType',

View File

@@ -0,0 +1,104 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<DictSelect
dict-code="ICType"
:placeholder="`IC卡类型`"
style="width: 120px"
v-model:value="where.typeName"
@done="onType"
/>
<a-input-search
allow-clear
placeholder="请输入关键词"
v-model:value="where.keywords"
@pressEnter="search"
@search="search"
>
<template #addonBefore>
<a-select v-model:value="type" style="width: 100px; margin: -5px -12px">
<a-select-option value="userId">用户ID</a-select-option>
<a-select-option value="username">真实姓名</a-select-option>
<a-select-option value="phone">手机号</a-select-option>
<a-select-option value="cardNum">IC卡数字</a-select-option>
</a-select>
</template>
</a-input-search>
<a-button @click="reset">重置</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import useSearch from '@/utils/use-search';
import { UserCardParam } from '@/api/booking/userCard/model';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: UserCardParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
const type = ref('phone');
// 新增
const add = () => {
emit('add');
};
// 表单数据
const { where, resetFields } = useSearch<UserCardParam>({
type: undefined,
userId: undefined,
phone: undefined,
keywords: undefined
});
const search = () => {
if (type.value == 'userId') {
where.userId = Number(where.keywords);
where.keywords = undefined;
emit('search', where);
}
if (type.value == 'username') {
where.username = where.keywords;
where.keywords = undefined;
emit('search', where);
}
if (type.value == 'phone') {
where.phone = where.keywords;
where.keywords = undefined;
emit('search', where);
}
if (type.value == 'cardNum') {
where.cardNum = where.keywords;
where.keywords = undefined;
emit('search', where);
}
// emit('search', where);
};
/* 重置 */
const reset = () => {
resetFields();
search();
};
const onType = (item: any) => {
where.type = item.key;
emit('search', where);
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,492 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑会员卡' : '添加会员卡'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="用户id" name="userId">
<a-input
allow-clear
placeholder="请输入用户id"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="sid场馆id集合适用的场馆" name="sid">
<a-input
allow-clear
placeholder="请输入sid场馆id集合适用的场馆"
v-model:value="form.sid"
/>
</a-form-item>
<a-form-item label="用户id" name="uid">
<a-input
allow-clear
placeholder="请输入用户id"
v-model:value="form.uid"
/>
</a-form-item>
<a-form-item label="vip卡id" name="vid">
<a-input
allow-clear
placeholder="请输入vip卡id"
v-model:value="form.vid"
/>
</a-form-item>
<a-form-item label="开卡人id" name="aid">
<a-input
allow-clear
placeholder="请输入开卡人id"
v-model:value="form.aid"
/>
</a-form-item>
<a-form-item label="微信订单号" name="wechatOrder">
<a-input
allow-clear
placeholder="请输入微信订单号"
v-model:value="form.wechatOrder"
/>
</a-form-item>
<a-form-item label="卡号" name="code">
<a-input
allow-clear
placeholder="请输入卡号"
v-model:value="form.code"
/>
</a-form-item>
<a-form-item label="会员卡名称" name="name">
<a-input
allow-clear
placeholder="请输入会员卡名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="真实姓名" name="username">
<a-input
allow-clear
placeholder="请输入真实姓名"
v-model:value="form.username"
/>
</a-form-item>
<a-form-item label="手机号码" name="phone">
<a-input
allow-clear
placeholder="请输入手机号码"
v-model:value="form.phone"
/>
</a-form-item>
<a-form-item label="vip购卡价格" name="price">
<a-input
allow-clear
placeholder="请输入vip购卡价格"
v-model:value="form.price"
/>
</a-form-item>
<a-form-item label="会员卡介绍" name="desc">
<a-input
allow-clear
placeholder="请输入会员卡介绍"
v-model:value="form.desc"
/>
</a-form-item>
<a-form-item label="会员卡说明" name="info">
<a-input
allow-clear
placeholder="请输入会员卡说明"
v-model:value="form.info"
/>
</a-form-item>
<a-form-item label="vip卡折扣率" name="discount">
<a-input
allow-clear
placeholder="请输入vip卡折扣率"
v-model:value="form.discount"
/>
</a-form-item>
<a-form-item label="使用次数" name="count">
<a-input
allow-clear
placeholder="请输入使用次数"
v-model:value="form.count"
/>
</a-form-item>
<a-form-item label="每使用一次减少的金额" name="eachMoney">
<a-input
allow-clear
placeholder="请输入每使用一次减少的金额"
v-model:value="form.eachMoney"
/>
</a-form-item>
<a-form-item label="剩余金额" name="remainingMoney">
<a-input
allow-clear
placeholder="请输入剩余金额"
v-model:value="form.remainingMoney"
/>
</a-form-item>
<a-form-item label="续费累加次数" name="number">
<a-input
allow-clear
placeholder="请输入续费累加次数"
v-model:value="form.number"
/>
</a-form-item>
<a-form-item label="剩余次数" name="num">
<a-input
allow-clear
placeholder="请输入剩余次数"
v-model:value="form.num"
/>
</a-form-item>
<a-form-item label="付款状态,1已付款2未付款" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="会员卡年限" name="term">
<a-input
allow-clear
placeholder="请输入会员卡年限"
v-model:value="form.term"
/>
</a-form-item>
<a-form-item label="月限" name="month">
<a-input
allow-clear
placeholder="请输入月限"
v-model:value="form.month"
/>
</a-form-item>
<a-form-item label="IC卡类型1年卡2次卡3月卡4会员IC卡5充值卡 " name="type">
<a-input
allow-clear
placeholder="请输入IC卡类型1年卡2次卡3月卡4会员IC卡5充值卡 "
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="卡类型1成人卡2儿童卡" name="cardType">
<a-input
allow-clear
placeholder="请输入卡类型1成人卡2儿童卡"
v-model:value="form.cardType"
/>
</a-form-item>
<a-form-item label="vip卡等级类型1特殊vip卡2普通vip卡" name="vipType">
<a-input
allow-clear
placeholder="请输入vip卡等级类型1特殊vip卡2普通vip卡"
v-model:value="form.vipType"
/>
</a-form-item>
<a-form-item label="特殊卡开发凭证图" name="pic">
<a-input
allow-clear
placeholder="请输入特殊卡开发凭证图"
v-model:value="form.pic"
/>
</a-form-item>
<a-form-item label="价格组" name="prices">
<a-input
allow-clear
placeholder="请输入价格组"
v-model:value="form.prices"
/>
</a-form-item>
<a-form-item label="1微信支付2支付宝支付3现金4POS机刷卡15平安健康卡" name="payType">
<a-input
allow-clear
placeholder="请输入1微信支付2支付宝支付3现金4POS机刷卡15平安健康卡"
v-model:value="form.payType"
/>
</a-form-item>
<a-form-item label="是否赠送积分1赠送2不赠送" name="isIntegral">
<a-input
allow-clear
placeholder="请输入是否赠送积分1赠送2不赠送"
v-model:value="form.isIntegral"
/>
</a-form-item>
<a-form-item label="是否已开具发票1已开发票2未开发票" name="isInvoice">
<a-input
allow-clear
placeholder="请输入是否已开具发票1已开发票2未开发票"
v-model:value="form.isInvoice"
/>
</a-form-item>
<a-form-item label="vip卡到期时间" name="expireTime">
<a-input
allow-clear
placeholder="请输入vip卡到期时间"
v-model:value="form.expireTime"
/>
</a-form-item>
<a-form-item label="紧急联系人" name="urgentName">
<a-input
allow-clear
placeholder="请输入紧急联系人"
v-model:value="form.urgentName"
/>
</a-form-item>
<a-form-item label="紧急联系人号码" name="urgentPhone">
<a-input
allow-clear
placeholder="请输入紧急联系人号码"
v-model:value="form.urgentPhone"
/>
</a-form-item>
<a-form-item label="卡号" name="cardNum">
<a-input
allow-clear
placeholder="请输入卡号"
v-model:value="form.cardNum"
/>
</a-form-item>
<a-form-item label="密码" name="password">
<a-input
allow-clear
placeholder="请输入密码"
v-model:value="form.password"
/>
</a-form-item>
<a-form-item label="使用时间" name="useTime">
<a-input
allow-clear
placeholder="请输入使用时间"
v-model:value="form.useTime"
/>
</a-form-item>
<a-form-item label="" name="updateTime">
<a-input
allow-clear
placeholder="请输入"
v-model:value="form.updateTime"
/>
</a-form-item>
<a-form-item label="身份证号码" name="idCard">
<a-input
allow-clear
placeholder="请输入身份证号码"
v-model:value="form.idCard"
/>
</a-form-item>
<a-form-item label="备注" name="remark">
<a-input
allow-clear
placeholder="请输入备注"
v-model:value="form.remark"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="排序号" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addUserCard, updateUserCard } from '@/api/booking/userCard';
import { UserCard } from '@/api/booking/userCard/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: UserCard | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<UserCard>({
id: undefined,
userId: undefined,
sid: undefined,
uid: undefined,
vid: undefined,
aid: undefined,
wechatOrder: undefined,
code: undefined,
name: undefined,
username: undefined,
phone: undefined,
price: undefined,
desc: undefined,
info: undefined,
discount: undefined,
count: undefined,
eachMoney: undefined,
remainingMoney: undefined,
number: undefined,
num: undefined,
status: undefined,
term: undefined,
month: undefined,
type: undefined,
cardType: undefined,
vipType: undefined,
pic: undefined,
prices: undefined,
payType: undefined,
isIntegral: undefined,
isInvoice: undefined,
expireTime: undefined,
urgentName: undefined,
urgentPhone: undefined,
cardNum: undefined,
password: undefined,
useTime: undefined,
createTime: undefined,
updateTime: undefined,
idCard: undefined,
remark: undefined,
comments: undefined,
sortNumber: undefined,
tenantId: undefined,
userCardId: undefined,
userCardName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
userCardName: [
{
required: true,
type: 'string',
message: '请填写会员卡名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateUserCard : addUserCard;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,505 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="userCardId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
:scroll="{ x: 800 }"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'action'">
<a-space>
<a class="ele-text-success">解除绑定</a>
<a-divider type="vertical" />
<a class="ele-text-warning">变更绑定</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">注销</a>
</a-popconfirm>
<!-- <a-divider type="vertical" />-->
<!-- <a @click="openEdit(record)">修改</a>-->
<!-- <a-divider type="vertical" />-->
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<UserCardEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { EleProTable, formatNumber } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import UserCardEdit from './components/userCardEdit.vue';
import {
pageUserCard,
removeUserCard,
removeBatchUserCard
} from '@/api/booking/userCard';
import type { UserCard, UserCardParam } from '@/api/booking/userCard/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<UserCard[]>([]);
// 当前编辑数据
const current = ref<UserCard | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageUserCard({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '姓名',
dataIndex: 'username',
key: 'username',
align: 'center',
width: 120,
fixed: 'left'
},
{
title: 'IC卡号',
dataIndex: 'code',
key: 'code',
width: 120,
fixed: 'left',
align: 'center'
},
{
title: '手机号码',
dataIndex: 'phone',
key: 'phone',
align: 'center',
width: 120,
fixed: 'left'
},
{
title: '会员卡名称',
dataIndex: 'name',
key: 'name',
width: 180,
align: 'center'
},
{
title: '卡号',
dataIndex: 'cardNum',
key: 'cardNum',
width: 120,
align: 'center'
},
{
title: '可用场馆',
dataIndex: 'sid',
key: 'sid',
width: 120,
align: 'center'
},
{
title: '购卡价格',
dataIndex: 'price',
key: 'price',
align: 'center',
width: 120,
customRender: ({ text }) => `${formatNumber(text)}`
},
{
title: '紧急联系人',
dataIndex: 'urgentName',
key: 'urgentName',
width: 120,
align: 'center'
},
{
title: '紧急联系人号码',
dataIndex: 'urgentPhone',
key: 'urgentPhone',
align: 'center',
width: 120
},
{
title: 'vip卡折扣率',
dataIndex: 'discount',
key: 'discount',
width: 120,
align: 'center'
},
{
title: '使用次数',
dataIndex: 'count',
key: 'count',
width: 120,
align: 'center'
},
{
title: '剩余次数',
dataIndex: 'num',
key: 'num',
width: 120,
align: 'center'
},
{
title: '每使用一次减少的金额',
dataIndex: 'eachMoney',
key: 'eachMoney',
width: 120,
align: 'center',
customRender: ({ text }) => `${formatNumber(text)}`
},
{
title: '剩余金额',
dataIndex: 'remainingMoney',
key: 'remainingMoney',
width: 120,
align: 'center',
customRender: ({ text }) => `${formatNumber(text)}`
},
{
title: '月限',
dataIndex: 'month',
key: 'month',
width: 120,
align: 'center'
},
{
title: '会员卡年限',
dataIndex: 'term',
key: 'term',
width: 120,
align: 'center'
},
{
title: 'IC卡类型',
dataIndex: 'type',
key: 'type',
width: 120,
align: 'center',
customRender: ({ text }) =>
['-', '年卡', '次卡', '月卡', '会员IC卡', '充值卡'][text]
},
{
title: '是否赠送积分',
dataIndex: 'isIntegral',
key: 'isIntegral',
width: 120,
align: 'center',
customRender: ({ text }) => ['', '赠送', '不赠送'][text]
},
{
title: '支付状态',
dataIndex: 'status',
key: 'status',
width: 120,
align: 'center',
customRender: ({ text }) => ['未支付', '已支付'][text]
},
{
title: '支付方式',
dataIndex: 'payType',
key: 'payType',
width: 120,
align: 'center',
customRender: ({ text }) =>
[
'余额支付',
'微信支付',
'支付宝支付',
'现金',
'POS机刷卡',
'平安健康卡'
][text]
},
{
title: '是否已开具发票',
dataIndex: 'isInvoice',
key: 'isInvoice',
width: 120,
align: 'center',
customRender: ({ text }) => ['未开票', '已开票', '未开票'][text]
},
{
title: '到期时间',
dataIndex: 'expireTime',
key: 'expireTime',
align: 'center',
width: 180,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd HH:mm')
},
{
title: '购卡时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
width: 180,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
// {
// title: '用户id',
// dataIndex: 'uid',
// key: 'uid',
// width: 190,
// align: 'center',
// },
// {
// title: 'vip卡id',
// dataIndex: 'vid',
// key: 'vid',
// width: 190,
// align: 'center',
// },
// {
// title: '开卡人id',
// dataIndex: 'aid',
// key: 'aid',
// align: 'center',
// },
// {
// title: '微信订单号',
// dataIndex: 'wechatOrder',
// key: 'wechatOrder',
// width: 190,
// align: 'center',
// },
// {
// title: '会员卡介绍',
// dataIndex: 'desc',
// key: 'desc',
// align: 'center',
// },
// {
// title: '会员卡说明',
// dataIndex: 'info',
// key: 'info',
// width: 490,
// align: 'center',
// },
// {
// title: '续费累加次数',
// dataIndex: 'number',
// key: 'number',
// align: 'center',
// },
// {
// title: '卡类型1成人卡2儿童卡',
// dataIndex: 'cardType',
// key: 'cardType',
// align: 'center',
// },
// {
// title: 'vip卡等级类型1特殊vip卡2普通vip卡',
// dataIndex: 'vipType',
// key: 'vipType',
// align: 'center',
// },
// {
// title: '特殊卡开发凭证图',
// dataIndex: 'pic',
// key: 'pic',
// align: 'center',
// },
// {
// title: '价格组',
// dataIndex: 'prices',
// key: 'prices',
// align: 'center',
// },
// {
// title: '密码',
// dataIndex: 'password',
// key: 'password',
// align: 'center',
// },
// {
// title: '使用时间',
// dataIndex: 'useTime',
// key: 'useTime',
// align: 'center',
// },
// {
// title: '',
// dataIndex: 'updateTime',
// key: 'updateTime',
// align: 'center',
// },
// {
// title: '身份证号码',
// dataIndex: 'idCard',
// key: 'idCard',
// align: 'center',
// },
// {
// title: '备注',
// dataIndex: 'remark',
// key: 'remark',
// align: 'center',
// },
// {
// title: '备注',
// dataIndex: 'comments',
// key: 'comments',
// align: 'center',
// },
// {
// title: '排序号',
// dataIndex: 'sortNumber',
// key: 'sortNumber',
// align: 'center'
// },
{
title: '操作',
key: 'action',
width: 240,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: UserCardParam) => {
console.log(where);
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: UserCard) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: UserCard) => {
const hide = message.loading('请求中..', 0);
removeUserCard(row.userCardId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchUserCard(selection.value.map((d) => d.userCardId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: UserCard) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'UserCard'
};
</script>
<style lang="less" scoped></style>

View File

@@ -1,20 +1,19 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-input-search
allow-clear
v-model:value="where.keywords"
placeholder="请输入关键词"
@search="search"
@pressEnter="search"
/>
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
import useSearch from '@/utils/use-search';
import { UsersParam } from '@/api/booking/users/model';
const props = withDefaults(
defineProps<{
@@ -25,22 +24,12 @@
);
const emit = defineEmits<{
(e: 'search', where?: UsersParam): void;
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
//
const { where } = useSearch<UsersParam>({
keywords: ''
});
/* 搜索 */
const search = () => {
emit('search', where);
};
//
const add = () => {
emit('add');

View File

@@ -5,7 +5,7 @@
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑用户' : '添加用户'"
:title="isUpdate ? '编辑明细表' : '添加明细表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
@@ -19,143 +19,56 @@
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="用户唯一小程序id" name="openid">
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户唯一小程序id"
v-model:value="form.openid"
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="小程序用户秘钥" name="sessionKey">
<a-form-item label="IC卡类型1年卡2次卡3月卡4会员IC卡5充值卡 " name="type">
<a-input
allow-clear
placeholder="请输入小程序用户秘钥"
v-model:value="form.sessionKey"
placeholder="请输入IC卡类型1年卡2次卡3月卡4会员IC卡5充值卡 "
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="用户名" name="username">
<a-form-item label="变动金额" name="money">
<a-input
allow-clear
placeholder="请输入用户名"
v-model:value="form.username"
placeholder="请输入变动金额"
v-model:value="form.money"
/>
</a-form-item>
<a-form-item label="头像地址" name="avatarUrl">
<a-form-item label="变动后余额" name="balance">
<a-input
allow-clear
placeholder="请输入头像地址"
v-model:value="form.avatarUrl"
/>
</a-form-item>
<a-form-item label="1男2女" name="gender">
<a-input
allow-clear
placeholder="请输入1男2女"
v-model:value="form.gender"
/>
</a-form-item>
<a-form-item label="国家" name="country">
<a-input
allow-clear
placeholder="请输入国家"
v-model:value="form.country"
/>
</a-form-item>
<a-form-item label="省份" name="province">
<a-input
allow-clear
placeholder="请输入省份"
v-model:value="form.province"
/>
</a-form-item>
<a-form-item label="城市" name="city">
<a-input
allow-clear
placeholder="请输入城市"
v-model:value="form.city"
/>
</a-form-item>
<a-form-item label="所在辖区" name="region">
<a-input
allow-clear
placeholder="请输入所在辖区"
v-model:value="form.region"
/>
</a-form-item>
<a-form-item label="手机号码" name="phone">
<a-input
allow-clear
placeholder="请输入手机号码"
v-model:value="form.phone"
/>
</a-form-item>
<a-form-item label="邮箱" name="email">
<a-input
allow-clear
placeholder="请输入邮箱"
v-model:value="form.email"
/>
</a-form-item>
<a-form-item label="邮箱是否验证, 0否, 1是" name="emailVerified">
<a-input
allow-clear
placeholder="请输入邮箱是否验证, 0否, 1是"
v-model:value="form.emailVerified"
/>
</a-form-item>
<a-form-item label="积分" name="points">
<a-input
allow-clear
placeholder="请输入积分"
v-model:value="form.points"
/>
</a-form-item>
<a-form-item label="余额" name="balance">
<a-input
allow-clear
placeholder="请输入余额"
placeholder="请输入变动后余额"
v-model:value="form.balance"
/>
</a-form-item>
<a-form-item label="注册时间" name="addTime">
<a-form-item label="管理员备注" name="remark">
<a-input
allow-clear
placeholder="请输入注册时间"
v-model:value="form.addTime"
placeholder="请输入管理员备注"
v-model:value="form.remark"
/>
</a-form-item>
<a-form-item label="" name="idcard">
<a-input allow-clear placeholder="请输入" v-model:value="form.idcard" />
</a-form-item>
<a-form-item label="" name="truename">
<a-form-item label="订单编号" name="orderNo">
<a-input
allow-clear
placeholder="请输入"
v-model:value="form.truename"
placeholder="请输入订单编号"
v-model:value="form.orderNo"
/>
</a-form-item>
<a-form-item label="是否管理员1是2否" name="isAdmin">
<a-form-item label="操作人ID" name="adminId">
<a-input
allow-clear
placeholder="请输入是否管理员1是2否"
v-model:value="form.isAdmin"
placeholder="请输入操作人ID"
v-model:value="form.adminId"
/>
</a-form-item>
<a-form-item label="客户端ID" name="clientId">
<a-input
allow-clear
placeholder="请输入客户端ID"
v-model:value="form.clientId"
/>
</a-form-item>
<a-form-item label="注册来源客户端 (APP、H5、小程序等)" name="platform">
<a-input
allow-clear
placeholder="请输入注册来源客户端 (APP、H5、小程序等)"
v-model:value="form.platform"
/>
</a-form-item>
<a-form-item label="排序" name="sortNumber">
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
@@ -172,7 +85,7 @@
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态" name="status">
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
@@ -185,6 +98,27 @@
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="商户ID" name="merchantId">
<a-input
allow-clear
placeholder="请输入商户ID"
v-model:value="form.merchantId"
/>
</a-form-item>
<a-form-item label="商户编码" name="merchantCode">
<a-input
allow-clear
placeholder="请输入商户编码"
v-model:value="form.merchantCode"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
@@ -193,8 +127,8 @@
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addUsers, updateUsers } from '@/api/booking/users';
import { Users } from '@/api/booking/users/model';
import { addUserCardLog, updateUserCardLog } from '@/api/booking/userCardLog';
import { UserCardLog } from '@/api/booking/userCardLog/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
@@ -212,7 +146,7 @@
//
visible: boolean;
//
data?: Users | null;
data?: UserCardLog | null;
}>();
const emit = defineEmits<{
@@ -229,34 +163,29 @@
const images = ref<ItemType[]>([]);
//
const form = reactive<Users>({
uid: undefined,
openid: undefined,
sessionKey: undefined,
username: undefined,
avatarUrl: undefined,
sex: undefined,
country: undefined,
province: undefined,
city: undefined,
region: undefined,
phone: undefined,
email: undefined,
emailVerified: undefined,
points: undefined,
const form = reactive<UserCardLog>({
logId: undefined,
userId: undefined,
type: undefined,
money: undefined,
balance: undefined,
addTime: undefined,
idCard: undefined,
realName: undefined,
isAdmin: undefined,
clientId: undefined,
platform: undefined,
remark: undefined,
orderNo: undefined,
adminId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
merchantId: undefined,
merchantCode: undefined,
tenantId: undefined,
createTime: undefined
createTime: undefined,
updateTime: undefined,
userCardLogId: undefined,
userCardLogName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
@@ -266,11 +195,11 @@
//
const rules = reactive({
userName: [
userCardLogName: [
{
required: true,
type: 'string',
message: '请填写用户名称',
message: '请填写明细表名称',
trigger: 'blur'
}
]
@@ -282,12 +211,12 @@
url: data.path,
status: 'done'
});
form.avatarUrl = data.path;
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.avatarUrl = '';
form.image = '';
};
const { resetFields } = useForm(form, rules);
@@ -304,7 +233,7 @@
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateUsers : addUsers;
const saveOrUpdate = isUpdate.value ? updateUserCardLog : addUserCardLog;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
@@ -327,12 +256,12 @@
images.value = [];
if (props.data) {
assignObject(form, props.data);
if (props.data.avatarUrl) {
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.avatarUrl,
url: props.data.image,
status: 'done'
});
})
}
isUpdate.value = true;
} else {

View File

@@ -4,7 +4,7 @@
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="uid"
row-key="userCardLogId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
@@ -21,36 +21,23 @@
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'avatarUrl'">
<a-avatar
:size="36"
:src="`${record.avatarUrl}`"
style="margin-right: 4px"
>
<template #icon>
<UserOutlined />
</template>
</a-avatar>
</template>
<template v-if="column.key === 'uid'">
{{ record }}
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
{{ record }}
<a-tag v-if="record.status === 1" color="green">启用</a-tag>
<a-tag v-if="record.status === 2" color="red">禁用</a-tag>
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a>积分充值</a>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a>分配特殊卡</a>
<!-- <a-popconfirm-->
<!-- title="确定要删除此记录吗?"-->
<!-- @confirm="remove(record)"-->
<!-- >-->
<!-- <a class="ele-text-danger">删除</a>-->
<!-- </a-popconfirm>-->
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
@@ -58,7 +45,7 @@
</a-card>
<!-- 编辑弹窗 -->
<UserEdit v-model:visible="showEdit" :data="current" @done="reload" />
<UserCardLogEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
@@ -66,10 +53,7 @@
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import {
ExclamationCircleOutlined,
UserOutlined
} from '@ant-design/icons-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
@@ -77,21 +61,17 @@
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import UserEdit from './components/userEdit.vue';
import {
pageUsers,
removeBatchUsers,
removeUsers
} from '@/api/booking/users';
import type { Users, UsersParam } from '@/api/booking/users/model';
import UserCardLogEdit from './components/userCardLogEdit.vue';
import { pageUserCardLog, removeUserCardLog, removeBatchUserCardLog } from '@/api/booking/userCardLog';
import type { UserCardLog, UserCardLogParam } from '@/api/booking/userCardLog/model';
//
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
//
const selection = ref<Users[]>([]);
const selection = ref<UserCardLog[]>([]);
//
const current = ref<Users | null>(null);
const current = ref<UserCardLog | null>(null);
//
const showEdit = ref(false);
//
@@ -110,7 +90,7 @@
if (filters) {
where.status = filters.status;
}
return pageUsers({
return pageUserCardLog({
...where,
...orders,
page,
@@ -121,95 +101,105 @@
//
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'uid',
key: 'uid',
width: 90
},
{
title: '头像',
dataIndex: 'avatarUrl',
key: 'avatarUrl',
align: 'center'
},
{
title: '用户名',
dataIndex: 'username',
key: 'username',
align: 'center'
},
{
title: '手机号码',
dataIndex: 'phone',
key: 'phone',
align: 'center'
},
{
title: '性别',
dataIndex: 'sexName',
key: 'sexName',
align: 'center'
},
{
title: '国家',
dataIndex: 'country',
key: 'country',
title: '主键ID',
dataIndex: 'logId',
key: 'logId',
align: 'center',
hideInTable: true
width: 90,
},
{
title: '省份',
dataIndex: 'province',
key: 'province',
align: 'center'
},
{
title: '城市',
dataIndex: 'city',
key: 'city',
align: 'center'
},
{
title: '所在辖区',
dataIndex: 'region',
key: 'region',
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
hideInTable: true
},
{
title: '邮箱是否验证, 0否, 1是',
dataIndex: 'emailVerified',
key: 'emailVerified',
title: 'IC卡类型1年卡2次卡3月卡4会员IC卡5充值卡 ',
dataIndex: 'type',
key: 'type',
align: 'center',
hideInTable: true
},
{
title: '积分',
dataIndex: 'points',
key: 'points',
align: 'center'
title: '变动金额',
dataIndex: 'money',
key: 'money',
align: 'center',
},
{
title: '余额',
title: '变动后余额',
dataIndex: 'balance',
key: 'balance',
align: 'center'
align: 'center',
},
{
title: '状态',
title: '管理员备注',
dataIndex: 'remark',
key: 'remark',
align: 'center',
},
{
title: '订单编号',
dataIndex: 'orderNo',
key: 'orderNo',
align: 'center',
},
{
title: '操作人ID',
dataIndex: 'adminId',
key: 'adminId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center'
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '商户ID',
dataIndex: 'merchantId',
key: 'merchantId',
align: 'center',
},
{
title: '商户编码',
dataIndex: 'merchantCode',
key: 'merchantCode',
align: 'center',
},
{
title: '注册时间',
dataIndex: 'addTime',
key: 'addTime',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
@@ -221,13 +211,13 @@
]);
/* 搜索 */
const reload = (where?: UsersParam) => {
const reload = (where?: UserCardLogParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: Users) => {
const openEdit = (row?: UserCardLog) => {
current.value = row ?? null;
showEdit.value = true;
};
@@ -238,9 +228,9 @@
};
/* 删除单个 */
const remove = (row: Users) => {
const remove = (row: UserCardLog) => {
const hide = message.loading('请求中..', 0);
removeUsers(row.uid)
removeUserCardLog(row.userCardLogId)
.then((msg) => {
hide();
message.success(msg);
@@ -265,7 +255,7 @@
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchUsers(selection.value.map((d) => d.uid))
removeBatchUserCardLog(selection.value.map((d) => d.userCardLogId))
.then((msg) => {
hide();
message.success(msg);
@@ -285,7 +275,7 @@
};
/* 自定义行属性 */
const customRow = (record: Users) => {
const customRow = (record: UserCardLog) => {
return {
//
onClick: () => {
@@ -302,7 +292,7 @@
<script lang="ts">
export default {
name: 'Users'
name: 'UserCardLog'
};
</script>

View File

@@ -57,6 +57,27 @@
v-model:value="form.target"
/>
</a-form-item>
<a-form-item label="菜单类型" name="type">
<a-select
v-model:value="form.type"
placeholder="菜单类型"
:style="`width: 200px`"
>
<a-select-option :value="0">会员功能</a-select-option>
<a-select-option :value="1">订单管理</a-select-option>
<a-select-option :value="2">首页导航</a-select-option>
<a-select-option :value="3">商城导航</a-select-option>
<a-select-option :value="4">管理中心</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="管理人员可见" name="adminShow">
<a-switch
checked-children=""
un-checked-children=""
:checked="form.adminShow === 1"
@update:checked="updateAdminShow"
/>
</a-form-item>
<a-form-item label="排序" name="sortNumber">
<a-input-number
:min="0"
@@ -127,6 +148,7 @@
position: undefined,
active: undefined,
userId: 0,
adminShow: undefined,
home: undefined,
sortNumber: 100,
comments: '',
@@ -172,6 +194,10 @@
form.icon = '';
};
const updateAdminShow = (value: boolean) => {
form.adminShow = value ? 1 : 0;
};
// 预设颜色
const predefineColors = ref([
'#40a9ff',

View File

@@ -12,7 +12,8 @@
>菜单类型</span
>
<a-radio-group v-model:value="where.type" @change="handleSearch">
<a-radio-button :value="0">功能图标</a-radio-button>
<a-radio-button :value="0">会员功能</a-radio-button>
<a-radio-button :value="4">管理中心</a-radio-button>
<a-radio-button :value="1">订单图标</a-radio-button>
</a-radio-group>
</a-space>

View File

@@ -79,7 +79,7 @@
</template>
<script lang="ts" setup>
import { createVNode, ref, unref, watch } from 'vue';
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
@@ -108,8 +108,6 @@
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 页面标题
const title = getPageTitle();
const type = ref<number>(2);
@@ -121,8 +119,6 @@
showOrderCard: true,
showToolsCard: true
});
// 菜单列表
const list = ref<any[]>();
// 表格数据源
const datasource: DatasourceFunction = ({
@@ -135,7 +131,6 @@
if (filters) {
where.status = filters.status;
}
where.type = type.value;
return pageMpMenu({
...where,
...orders,
@@ -195,7 +190,11 @@
/* 搜索 */
const reload = (where?: MpMenuParam) => {
type.value = Number(where?.type) || 0;
if (where?.type) {
type.value = Number(where?.type);
} else {
type.value = 0;
}
refresh.value = !refresh.value;
selection.value = [];
tableRef?.value?.reload({ where: where });