|
|
@@ -0,0 +1,420 @@
|
|
|
+<script setup lang="tsx">
|
|
|
+import { ref, watch, PropType, defineExpose } from 'vue'
|
|
|
+import {
|
|
|
+ FormRules,
|
|
|
+ ElTabs,
|
|
|
+ ElTabPane,
|
|
|
+ ElTable,
|
|
|
+ ElTableColumn,
|
|
|
+ ElPagination,
|
|
|
+ ElFormItem,
|
|
|
+ ElForm,
|
|
|
+ ElInput,
|
|
|
+ ElSelect,
|
|
|
+ ElOption,
|
|
|
+ ElDatePicker,
|
|
|
+ ElDivider,
|
|
|
+ ElSwitch,
|
|
|
+ ElTag,
|
|
|
+ ElDescriptions,
|
|
|
+ ElDescriptionsItem
|
|
|
+} from 'element-plus'
|
|
|
+import {
|
|
|
+ getBalanceLog,
|
|
|
+ getSpreadList,
|
|
|
+ getBrokerageLog
|
|
|
+ // getBillLog
|
|
|
+} from '@/api/user'
|
|
|
+import { userData } from '@/api/user/types'
|
|
|
+import { useValidator } from '@/hooks/web/useValidator'
|
|
|
+import InputPassword from '@/components/InputPassword/src/InputPassword.vue'
|
|
|
+import { formatToDate } from '@/utils/dateUtil'
|
|
|
+const { required, phone } = useValidator()
|
|
|
+const modelValue = defineModel<boolean>()
|
|
|
+const props = defineProps({
|
|
|
+ userDetail: {
|
|
|
+ type: Object as PropType<userData>,
|
|
|
+ default: () => ({})
|
|
|
+ },
|
|
|
+ levelList: {
|
|
|
+ type: Array as PropType<any[]>,
|
|
|
+ default: () => []
|
|
|
+ },
|
|
|
+ groupList: {
|
|
|
+ type: Array as PropType<any[]>,
|
|
|
+ default: () => []
|
|
|
+ }
|
|
|
+})
|
|
|
+const localUserDetail = ref<userData>({ ...props.userDetail })
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => props.userDetail,
|
|
|
+ (newVal) => {
|
|
|
+ localUserDetail.value = { ...newVal }
|
|
|
+ if (typeof newVal.birthday == 'number') {
|
|
|
+ localUserDetail.value.birthday = newVal.birthday ? formatToDate(newVal.birthday * 1000) : ''
|
|
|
+ localUserDetail.value.is_promoter = newVal.is_promoter == 1 ? true : false
|
|
|
+ localUserDetail.value.status = newVal.status == 1 ? true : false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { deep: true, immediate: true }
|
|
|
+)
|
|
|
+
|
|
|
+const rules = ref<FormRules>({
|
|
|
+ phone: [required('请填写手机号'), phone()],
|
|
|
+ pwd: [{}],
|
|
|
+ true_pwd: [
|
|
|
+ {
|
|
|
+ validator: (_, val, callback) => {
|
|
|
+ if (!val) return callback()
|
|
|
+ if (localUserDetail.value.pwd !== val) {
|
|
|
+ callback(new Error('两次密码不一致'))
|
|
|
+ } else {
|
|
|
+ callback()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ true_trade_pwd: [
|
|
|
+ {
|
|
|
+ validator: (_, val, callback) => {
|
|
|
+ if (!val) return callback()
|
|
|
+ if (localUserDetail.value.trade_pwd && localUserDetail.value.trade_pwd !== val) {
|
|
|
+ callback(new Error('两次密码不一致'))
|
|
|
+ } else {
|
|
|
+ callback()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+})
|
|
|
+const userRecordList = ref([
|
|
|
+ {
|
|
|
+ name: '佣金记录',
|
|
|
+ type: '3',
|
|
|
+ page: 1,
|
|
|
+ limit: 10,
|
|
|
+ total: 0,
|
|
|
+ request: getBrokerageLog,
|
|
|
+ data: [],
|
|
|
+ loading: true,
|
|
|
+ columns: [
|
|
|
+ {
|
|
|
+ label: '时间',
|
|
|
+ field: 'add_time'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '变动金额',
|
|
|
+ field: 'number'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '变动后余额',
|
|
|
+ field: 'balance'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '变动类型',
|
|
|
+ field: 'type'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '备注'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '余额记录',
|
|
|
+ type: '2',
|
|
|
+ page: 1,
|
|
|
+ limit: 10,
|
|
|
+ total: 0,
|
|
|
+ loading: true,
|
|
|
+ request: getBalanceLog,
|
|
|
+ data: [],
|
|
|
+ columns: [
|
|
|
+ {
|
|
|
+ label: '时间',
|
|
|
+ field: 'add_time'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '变动金额',
|
|
|
+ field: 'number'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '变动后余额',
|
|
|
+ field: 'balance'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '变动类型',
|
|
|
+ field: 'type'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '备注'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '推荐人列表',
|
|
|
+ type: '1',
|
|
|
+ page: 1,
|
|
|
+ limit: 10,
|
|
|
+ total: 100,
|
|
|
+ loading: true,
|
|
|
+ request: getSpreadList,
|
|
|
+ data: [],
|
|
|
+ columns: [
|
|
|
+ {
|
|
|
+ label: '用户ID',
|
|
|
+ field: 'uid'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '用户昵称',
|
|
|
+ field: 'nickname'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '用户手机号',
|
|
|
+ field: 'phone'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '用户余额',
|
|
|
+ field: 'now_money'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+])
|
|
|
+const changeTable = (row: any) => {
|
|
|
+ for (let index = 0; index < userRecordList.value.length; index++) {
|
|
|
+ const element = userRecordList.value[index]
|
|
|
+ if (row == element.type) {
|
|
|
+ if (element.loading) {
|
|
|
+ element
|
|
|
+ .request(
|
|
|
+ {
|
|
|
+ page: element.page,
|
|
|
+ limit: element.limit
|
|
|
+ },
|
|
|
+ props.userDetail.uid
|
|
|
+ )
|
|
|
+ .then((res) => {
|
|
|
+ element.data = res.data.list
|
|
|
+ element.total = res.data.total
|
|
|
+ element.loading = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+const changePage = (row: any, item) => {
|
|
|
+ console.log(row, item, 'changePage')
|
|
|
+}
|
|
|
+const getFormData = () => {
|
|
|
+ const formData: userData = {
|
|
|
+ uid: localUserDetail.value.uid,
|
|
|
+ real_name: localUserDetail.value.real_name,
|
|
|
+ phone: localUserDetail.value.phone,
|
|
|
+ pwd: localUserDetail.value.pwd,
|
|
|
+ true_pwd: localUserDetail.value.true_pwd,
|
|
|
+ trade_pwd: localUserDetail.value.trade_pwd,
|
|
|
+ true_trade_pwd: localUserDetail.value.true_trade_pwd,
|
|
|
+ sex: localUserDetail.value.sex,
|
|
|
+ spread_uid: localUserDetail.value.spread_uid,
|
|
|
+ is_promoter: localUserDetail.value.is_promoter ? 1 : 0,
|
|
|
+ card_id: localUserDetail.value.card_id,
|
|
|
+ birthday: formatToDate(localUserDetail.value.birthday),
|
|
|
+ mark: localUserDetail.value.mark,
|
|
|
+ status: localUserDetail.value.status ? 1 : 0,
|
|
|
+ level: localUserDetail.value.level,
|
|
|
+ group_id: localUserDetail.value.group_id
|
|
|
+ }
|
|
|
+ return formData
|
|
|
+}
|
|
|
+defineExpose({
|
|
|
+ getFormData
|
|
|
+})
|
|
|
+
|
|
|
+const getLabel = (list, id) => {
|
|
|
+ // 检查列表是否存在且为数组类型,若不满足条件则返回null
|
|
|
+ if (!list || !Array.isArray(list)) return null
|
|
|
+
|
|
|
+ // 在列表中查找匹配给定ID的元素
|
|
|
+ const item = list.find((e) => e.value === id)
|
|
|
+
|
|
|
+ // 如果找到匹配的元素,则返回该元素的标签;否则,返回null
|
|
|
+ return item ? item.label : null
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <ElTabs type="border-card" @tab-change="changeTable">
|
|
|
+ <ElTabPane label="用户信息">
|
|
|
+ <div v-show="modelValue" class="p-20px">
|
|
|
+ <el-form label-width="110px" inline :rules="rules" :model="localUserDetail">
|
|
|
+ <ElDivider content-position="left"
|
|
|
+ ><span class="font-size-16px">基本信息</span></ElDivider
|
|
|
+ >
|
|
|
+ <el-form-item class="w-50%" label="用户编号" prop="uid">
|
|
|
+ <el-input disabled v-model="localUserDetail.uid" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item class="w-50%" label="真实姓名" prop="real_name">
|
|
|
+ <el-input v-model="localUserDetail.real_name" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item class="w-50%" label="手机号" prop="phone">
|
|
|
+ <el-input type="number" v-model="localUserDetail.phone" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="生日" prop="birthday">
|
|
|
+ <el-date-picker type="date" v-model="localUserDetail.birthday" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="身份证" prop="card_id">
|
|
|
+ <el-input v-model="localUserDetail.card_id" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="性别" prop="sex">
|
|
|
+ <el-select v-model="localUserDetail.sex">
|
|
|
+ <el-option label="保密" :value="0" />
|
|
|
+ <el-option label="男" :value="1" />
|
|
|
+ <el-option label="女" :value="2" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <ElDivider content-position="left"><span class="font-size-16px">密码</span></ElDivider>
|
|
|
+ <el-form-item class="w-50%" label="登录密码" prop="pwd">
|
|
|
+ <InputPassword class="w-100%" strength v-model="localUserDetail.pwd" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="确认密码" prop="true_pwd">
|
|
|
+ <InputPassword class="w-100%" strength v-model="localUserDetail.true_pwd" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="交易密码" prop="trade_pwd">
|
|
|
+ <el-input
|
|
|
+ maxlength="6"
|
|
|
+ minlength="6"
|
|
|
+ type="password"
|
|
|
+ v-model="localUserDetail.trade_pwd"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="确认交易密码" prop="true_trade_pwd">
|
|
|
+ <el-input
|
|
|
+ maxlength="6"
|
|
|
+ minlength="6"
|
|
|
+ type="password"
|
|
|
+ v-model="localUserDetail.true_trade_pwd"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <ElDivider class="w-50%" content-position="left"
|
|
|
+ ><span class="font-size-16px">用户概况</span></ElDivider
|
|
|
+ >
|
|
|
+ <el-form-item class="w-50%" label="用户分组" prop="group_id">
|
|
|
+ <el-select v-model="localUserDetail.group_id">
|
|
|
+ <el-option
|
|
|
+ v-for="(item, index) in groupList"
|
|
|
+ :key="index"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="会员等级" prop="level">
|
|
|
+ <el-select v-model="localUserDetail.level">
|
|
|
+ <el-option
|
|
|
+ v-for="(item, index) in levelList"
|
|
|
+ :key="index"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="推广员" prop="is_promoter">
|
|
|
+ <el-switch v-model="localUserDetail.is_promoter" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="状态" prop="status">
|
|
|
+ <el-switch v-model="localUserDetail.status" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-50%" label="推荐人ID" prop="spread_uid">
|
|
|
+ <el-input v-model="localUserDetail.spread_uid" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="w-100%" label="备注" prop="mark">
|
|
|
+ <el-input type="textarea" :rows="2" v-model="localUserDetail.mark" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <div v-show="!modelValue" class="p-20px">
|
|
|
+ <ElDivider content-position="left"><span class="font-size-16px">基本信息</span></ElDivider>
|
|
|
+ <el-descriptions>
|
|
|
+ <el-descriptions-item label="用户编号">{{ localUserDetail.uid }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="真实姓名">{{
|
|
|
+ localUserDetail.real_name
|
|
|
+ }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="手机号">{{ localUserDetail.phone }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="生日">
|
|
|
+ {{ localUserDetail.birthday ? formatToDate(localUserDetail.birthday) : '' }}
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="身份证">
|
|
|
+ {{ localUserDetail.card_id }}
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="性别">
|
|
|
+ <span v-if="localUserDetail.sex === 0">保密</span>
|
|
|
+ <span v-else-if="localUserDetail.sex === 1">男</span>
|
|
|
+ <span v-else-if="localUserDetail.sex === 2">女</span>
|
|
|
+ </el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+ <ElDivider content-position="left"><span class="font-size-16px">密码</span></ElDivider>
|
|
|
+ <el-descriptions>
|
|
|
+ <el-descriptions-item label="登录密码"> ****** </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="交易密码"> ****** </el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+ <ElDivider content-position="left"><span class="font-size-16px">用户概况</span></ElDivider>
|
|
|
+ <el-descriptions>
|
|
|
+ <el-descriptions-item label="用户分组">
|
|
|
+ {{ getLabel(groupList, localUserDetail.group_id) || '' }}
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="会员等级">
|
|
|
+ {{ getLabel(levelList, localUserDetail.level) || '' }}
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="推广员">
|
|
|
+ <ElTag v-if="localUserDetail.is_promoter" size="small" type="success">开启</ElTag>
|
|
|
+ <ElTag v-else size="small" type="danger">关闭</ElTag>
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="状态">
|
|
|
+ <ElTag v-if="localUserDetail.status" size="small" type="success">启用</ElTag>
|
|
|
+ <ElTag v-else size="small" type="danger">禁用</ElTag>
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="推荐人ID">
|
|
|
+ {{ localUserDetail.spread_uid }}
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="备注">
|
|
|
+ {{ localUserDetail.mark }}
|
|
|
+ </el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+ </div>
|
|
|
+ </ElTabPane>
|
|
|
+ <ElTabPane
|
|
|
+ :label="item.name"
|
|
|
+ :name="item.type"
|
|
|
+ v-for="(item, index) in userRecordList"
|
|
|
+ :key="index"
|
|
|
+ >
|
|
|
+ <ElTable v-loading="item.loading" :data="item.data" stripe>
|
|
|
+ <ElTableColumn
|
|
|
+ v-for="(ls, ind) in item.columns"
|
|
|
+ :key="ind"
|
|
|
+ :prop="ls.field"
|
|
|
+ :label="ls.label"
|
|
|
+ />
|
|
|
+ </ElTable>
|
|
|
+ <ElPagination
|
|
|
+ @change="changePage($event, item)"
|
|
|
+ v-model:current-page="item.page"
|
|
|
+ v-model:page-size="item.limit"
|
|
|
+ layout="sizes, prev, pager, next, jumper, ->, total"
|
|
|
+ :page-sizes="[10, 20, 30, 40, 50, 100]"
|
|
|
+ class="mt-10px"
|
|
|
+ :total="item.total"
|
|
|
+ />
|
|
|
+ </ElTabPane>
|
|
|
+ </ElTabs>
|
|
|
+</template>
|
|
|
+<style lang="less" scoped>
|
|
|
+:deep(.el-form-item) {
|
|
|
+ &.el-form-item {
|
|
|
+ margin-right: 0 !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|