BUG修复,及部分页面增加按钮权限
This commit is contained in:
parent
2f54ebef78
commit
6a714a77a9
|
|
@ -1,58 +1,65 @@
|
|||
<template>
|
||||
<el-dialog :model-value="visible" :title="title" :width="width" :destroy-on-close="destroyOnClose"
|
||||
:fullscreen="fullscreen"
|
||||
@close="handleClose" v-bind="$attrs">
|
||||
<!-- 对话框内容插槽 -->
|
||||
<slot />
|
||||
<el-dialog
|
||||
:model-value="visible"
|
||||
:title="title"
|
||||
:width="width"
|
||||
align-center
|
||||
:destroy-on-close="destroyOnClose"
|
||||
:fullscreen="fullscreen"
|
||||
@close="handleClose"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<!-- 对话框内容插槽 -->
|
||||
<slot />
|
||||
|
||||
<!-- 底部按钮插槽 -->
|
||||
<template #footer v-if="showFooter">
|
||||
<slot name="footer">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
||||
</slot>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 底部按钮插槽 -->
|
||||
<template #footer v-if="showFooter">
|
||||
<slot name="footer">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
||||
</slot>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
visible: boolean
|
||||
title: string
|
||||
width?: string | number
|
||||
destroyOnClose?: boolean
|
||||
type?: string
|
||||
showFooter?: boolean
|
||||
fullscreen?: boolean
|
||||
visible: boolean
|
||||
title: string
|
||||
width?: string | number
|
||||
destroyOnClose?: boolean
|
||||
type?: string
|
||||
showFooter?: boolean
|
||||
fullscreen?: boolean
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:visible', value: boolean): void
|
||||
(e: 'confirm'): void
|
||||
(e: 'cancel'): void
|
||||
(e: 'close'): void
|
||||
(e: 'update:visible', value: boolean): void
|
||||
(e: 'confirm'): void
|
||||
(e: 'cancel'): void
|
||||
(e: 'close'): void
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
width: '750px',
|
||||
destroyOnClose: true,
|
||||
showFooter: true,
|
||||
fullscreen: false,
|
||||
width: '750px',
|
||||
destroyOnClose: true,
|
||||
showFooter: true,
|
||||
fullscreen: false,
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const handleConfirm = () => {
|
||||
emit('confirm')
|
||||
emit('confirm')
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false)
|
||||
emit('cancel')
|
||||
emit('update:visible', false)
|
||||
emit('cancel')
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
emit('close')
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,102 +1,130 @@
|
|||
<template>
|
||||
<div class="search-container">
|
||||
<el-form :model="searchForm" inline @submit.prevent>
|
||||
<!-- 动态生成的表单项 -->
|
||||
<template v-for="item in searchOptions" :key="item.prop">
|
||||
<el-form-item :label="item.label" :prop="item.prop" v-if="!item.slot"
|
||||
:style="{ minWidth: item.minWidth, width: item.width }">
|
||||
<!-- 输入框 -->
|
||||
<el-input v-if="item.type === 'input'" v-model="searchForm[item.prop]"
|
||||
:placeholder="item.placeholder || `请输入${item.label}`" :clearable="item.clearable ?? true"
|
||||
:disabled="item.disabled" @blur="handleBlur"/>
|
||||
<div class="search-container">
|
||||
<el-form :model="searchForm" inline @submit.prevent>
|
||||
<!-- 动态生成的表单项 -->
|
||||
<template v-for="item in searchOptions" :key="item.prop">
|
||||
<el-form-item
|
||||
v-auth="item.auth || ''"
|
||||
:label="item.label"
|
||||
:prop="item.prop"
|
||||
v-if="!item.slot"
|
||||
:style="{
|
||||
minWidth: item.minWidth,
|
||||
width: item.width,
|
||||
flex: item.width ? '0 0 auto' : '',
|
||||
}"
|
||||
>
|
||||
<!-- 输入框 -->
|
||||
<el-input
|
||||
v-if="item.type === 'input'"
|
||||
v-model="searchForm[item.prop]"
|
||||
:placeholder="item.placeholder || `请输入${item.label}`"
|
||||
:clearable="item.clearable ?? true"
|
||||
:disabled="item.disabled"
|
||||
@blur="handleBlur"
|
||||
/>
|
||||
|
||||
<!-- 选择器 -->
|
||||
<el-select v-else-if="item.type === 'select'" v-model="searchForm[item.prop]"
|
||||
:placeholder="item.placeholder || `请选择${item.label}`" :clearable="item.clearable ?? true"
|
||||
:disabled="item.disabled">
|
||||
<el-option v-for="option in item.options" :key="option.value" :label="option.label"
|
||||
:value="option.value" />
|
||||
</el-select>
|
||||
<!-- 选择器 -->
|
||||
<el-select
|
||||
v-else-if="item.type === 'select'"
|
||||
v-model="searchForm[item.prop]"
|
||||
:placeholder="item.placeholder || `请选择${item.label}`"
|
||||
:clearable="item.clearable ?? true"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in item.options"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<!-- 日期选择器(单个/范围) -->
|
||||
<el-date-picker v-else-if="item.type === 'date'" v-model="searchForm[item.prop]"
|
||||
:type="item.dateType || 'date'" :range-separator="item.rangeSeparator || '至'"
|
||||
:start-placeholder="item.startPlaceholder || '开始日期'"
|
||||
:end-placeholder="item.endPlaceholder || '结束日期'"
|
||||
:value-format="item.valueFormat || 'YYYY-MM-DD'" :clearable="item.clearable ?? true"
|
||||
:disabled-date="item.disabledDate" :locale="'zhCn'" />
|
||||
</el-form-item>
|
||||
<!-- 日期选择器(单个/范围) -->
|
||||
<el-date-picker
|
||||
v-else-if="item.type === 'date'"
|
||||
v-model="searchForm[item.prop]"
|
||||
:type="item.dateType || 'date'"
|
||||
:range-separator="item.rangeSeparator || '至'"
|
||||
:start-placeholder="item.startPlaceholder || '开始日期'"
|
||||
:end-placeholder="item.endPlaceholder || '结束日期'"
|
||||
:value-format="item.valueFormat || 'YYYY-MM-DD'"
|
||||
:clearable="item.clearable ?? true"
|
||||
:disabled-date="item.disabledDate"
|
||||
:locale="'zhCn'"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 自定义插槽项 -->
|
||||
<el-form-item :label="item.label" :prop="item.prop" v-else>
|
||||
<slot :name="item.prop" :form="searchForm" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
<!-- 自定义插槽项 -->
|
||||
<el-form-item :label="item.label" :prop="item.prop" v-else>
|
||||
<slot :name="item.prop" :form="searchForm" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<!-- 额外插槽:用于插入配置外的自定义项 -->
|
||||
<slot name="extra" :form="searchForm" />
|
||||
<!-- 额外插槽:用于插入配置外的自定义项 -->
|
||||
<slot name="extra" :form="searchForm" />
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="$emit('search')">
|
||||
{{ buttonConfig.searchText || '搜索' }}
|
||||
</el-button>
|
||||
<el-button @click="$emit('reset')">
|
||||
{{ buttonConfig.resetText || '重置' }}
|
||||
</el-button>
|
||||
<!-- 按钮区插槽 -->
|
||||
<slot name="button" :form="searchForm" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<!-- 操作按钮 -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="$emit('search')">
|
||||
{{ buttonConfig.searchText || '搜索' }}
|
||||
</el-button>
|
||||
<el-button @click="$emit('reset')">
|
||||
{{ buttonConfig.resetText || '重置' }}
|
||||
</el-button>
|
||||
<!-- 按钮区插槽 -->
|
||||
<slot name="button" :form="searchForm" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 定义配置项类型
|
||||
interface SearchOption {
|
||||
prop: string; // 绑定的表单字段名
|
||||
label: string; // 标签文本
|
||||
type: 'input' | 'select' | 'date'; // 表单类型
|
||||
slot?: boolean; // 是否为自定义插槽项
|
||||
placeholder?: string; // 占位符
|
||||
clearable?: boolean; // 是否显示清空按钮
|
||||
disabled?: boolean; // 是否禁用
|
||||
options?: { label: string; value: any }[]; // 下拉/单选/复选选项
|
||||
dateType?: 'date' | 'daterange' | 'datetime' | 'datetimerange'; // 日期选择器类型
|
||||
rangeSeparator?: string; // 日期范围分隔符
|
||||
startPlaceholder?: string; // 日期范围开始占位符
|
||||
endPlaceholder?: string; // 日期范围结束占位符
|
||||
valueFormat?: string; // 日期格式
|
||||
disabledDate?: (date: Date) => boolean; // 禁用日期函数
|
||||
width?: string; // 宽度
|
||||
minWidth?: string; // 最小宽度
|
||||
prop: string // 绑定的表单字段名
|
||||
label: string // 标签文本
|
||||
type: 'input' | 'select' | 'date' // 表单类型
|
||||
slot?: boolean // 是否为自定义插槽项
|
||||
placeholder?: string // 占位符
|
||||
clearable?: boolean // 是否显示清空按钮
|
||||
disabled?: boolean // 是否禁用
|
||||
options?: { label: string; value: any }[] // 下拉/单选/复选选项
|
||||
dateType?: 'date' | 'daterange' | 'datetime' | 'datetimerange' // 日期选择器类型
|
||||
rangeSeparator?: string // 日期范围分隔符
|
||||
startPlaceholder?: string // 日期范围开始占位符
|
||||
endPlaceholder?: string // 日期范围结束占位符
|
||||
valueFormat?: string // 日期格式
|
||||
disabledDate?: (date: Date) => boolean // 禁用日期函数
|
||||
width?: string // 宽度
|
||||
minWidth?: string // 最小宽度
|
||||
auth?: string // 最小宽度
|
||||
}
|
||||
|
||||
// 按钮配置类型
|
||||
interface ButtonConfig {
|
||||
searchText?: string;
|
||||
resetText?: string;
|
||||
searchText?: string
|
||||
resetText?: string
|
||||
}
|
||||
|
||||
// 组件Props
|
||||
const props = defineProps({
|
||||
searchForm: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
searchOptions: {
|
||||
type: Array as () => SearchOption[
|
||||
],
|
||||
required: true,
|
||||
},
|
||||
buttonConfig: {
|
||||
type: Object as () => ButtonConfig,
|
||||
default: () => ({}),
|
||||
}
|
||||
searchForm: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
searchOptions: {
|
||||
type: Array as () => SearchOption[],
|
||||
required: true,
|
||||
},
|
||||
buttonConfig: {
|
||||
type: Object as () => ButtonConfig,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
// 暴露事件
|
||||
const emit = defineEmits(['search', 'reset','blur-input'])
|
||||
const emit = defineEmits(['search', 'reset', 'blur-input'])
|
||||
// 3. 👇 关键:账户名输入完成 → 抛事件给父组件
|
||||
const handleBlur = () => {
|
||||
emit('blur-input')
|
||||
|
|
@ -105,24 +133,24 @@ const handleBlur = () => {
|
|||
|
||||
<style scoped lang="scss">
|
||||
.search-container {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.el-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
.el-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
.el-form-item {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.el-form-item {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
margin-right: 16px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-button) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
:deep(.el-button) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,17 +1,29 @@
|
|||
import type { Directive, DirectiveBinding } from 'vue'
|
||||
import {getStorage} from '@/utils/storage'
|
||||
|
||||
import { getStorage } from '@/utils/storage'
|
||||
|
||||
/**
|
||||
* v-auth 指令 - 包含权限则显示
|
||||
* v-auth 指令 - 包含任一权限则显示
|
||||
* 用法:v-auth="'admin'" 或 v-auth="'user:read,user:write'"
|
||||
*/
|
||||
export const authDirective: Directive = {
|
||||
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||
checkPermission(el, binding.value, true)
|
||||
checkPermission(el, binding.value, 'some')
|
||||
},
|
||||
updated(el: HTMLElement, binding: DirectiveBinding) {
|
||||
checkPermission(el, binding.value, true)
|
||||
checkPermission(el, binding.value, 'some')
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* v-auth-all 指令 - 包含全部权限才显示
|
||||
* 用法:v-auth-all="'user:read,user:write'"(必须同时拥有两个权限)
|
||||
*/
|
||||
export const authAllDirective: Directive = {
|
||||
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||
checkPermission(el, binding.value, 'every')
|
||||
},
|
||||
updated(el: HTMLElement, binding: DirectiveBinding) {
|
||||
checkPermission(el, binding.value, 'every')
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -21,10 +33,10 @@ export const authDirective: Directive = {
|
|||
*/
|
||||
export const authNotDirective: Directive = {
|
||||
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||
checkPermission(el, binding.value, false)
|
||||
checkPermission(el, binding.value, 'none')
|
||||
},
|
||||
updated(el: HTMLElement, binding: DirectiveBinding) {
|
||||
checkPermission(el, binding.value, false)
|
||||
checkPermission(el, binding.value, 'none')
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -32,28 +44,64 @@ export const authNotDirective: Directive = {
|
|||
* 权限检查核心逻辑
|
||||
* @param el DOM 元素
|
||||
* @param value 指令绑定的权限字符串(单个或逗号分隔的多个)
|
||||
* @param shouldContain true=包含时显示,false=不包含时显示
|
||||
* @param mode 'some'=任一满足, 'every'=全部满足, 'none'=不包含时显示
|
||||
*/
|
||||
function checkPermission(el: HTMLElement, value: string | string[], shouldContain: boolean) {
|
||||
if (!value) {
|
||||
shouldContain ? el.remove() : (el.style.display = '')
|
||||
function checkPermission(
|
||||
el: HTMLElement,
|
||||
value: string | string[],
|
||||
mode: 'some' | 'every' | 'none',
|
||||
) {
|
||||
// 空字符串/空数组时:some/every 模式展示,none 模式隐藏
|
||||
if (!value || (Array.isArray(value) && value.length === 0)) {
|
||||
if (mode === 'none') {
|
||||
el.remove()
|
||||
} else {
|
||||
el.style.display = ''
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 统一处理为字符串并分割
|
||||
const permissions = Array.isArray(value) ? value : value.split(',').map((p) => p.trim())
|
||||
// 统一处理为字符串数组
|
||||
const permissions = Array.isArray(value)
|
||||
? value.map((p) => String(p).trim()).filter(Boolean)
|
||||
: String(value)
|
||||
.split(',')
|
||||
.map((p) => p.trim())
|
||||
.filter(Boolean)
|
||||
|
||||
// 如果过滤后为空(比如传入 ",," 这种情况),同空值处理
|
||||
if (permissions.length === 0) {
|
||||
if (mode === 'none') {
|
||||
el.remove()
|
||||
} else {
|
||||
el.style.display = ''
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 白名单权限配置(可从后端获取或配置文件读取)
|
||||
const WHITE_LIST = getStorage('btnAuth');
|
||||
const WHITE_LIST: string[] = getStorage('btnAuth') || []
|
||||
|
||||
// 检查是否有任一权限在白名单中
|
||||
const hasPermission = permissions.some((p) => WHITE_LIST.includes(p))
|
||||
let hasPermission: boolean
|
||||
|
||||
// 根据 shouldContain 决定显示/隐藏
|
||||
if (shouldContain) {
|
||||
hasPermission ? (el.style.display = '') : el.remove()
|
||||
} else {
|
||||
hasPermission ? el.remove() : (el.style.display = '')
|
||||
switch (mode) {
|
||||
case 'some':
|
||||
// 任一权限满足即显示
|
||||
hasPermission = permissions.some((p) => WHITE_LIST.includes(p))
|
||||
hasPermission ? (el.style.display = '') : el.remove()
|
||||
break
|
||||
|
||||
case 'every':
|
||||
// 全部权限满足才显示
|
||||
hasPermission = permissions.every((p) => WHITE_LIST.includes(p))
|
||||
hasPermission ? (el.style.display = '') : el.remove()
|
||||
break
|
||||
|
||||
case 'none':
|
||||
// 不包含任一权限时显示
|
||||
hasPermission = permissions.some((p) => WHITE_LIST.includes(p))
|
||||
hasPermission ? el.remove() : (el.style.display = '')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,5 +110,6 @@ function checkPermission(el: HTMLElement, value: string | string[], shouldContai
|
|||
*/
|
||||
export function setupAuthDirective(app: any) {
|
||||
app.directive('auth', authDirective)
|
||||
app.directive('auth-all', authAllDirective)
|
||||
app.directive('auth-not', authNotDirective)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,14 +15,14 @@
|
|||
:highlight-current-row="false"
|
||||
>
|
||||
<!-- 操作列插槽 -->
|
||||
<template #operation="{ row }">
|
||||
<el-button type="primary" :disabled="row.status !== '1'" @click="handleAudit(row, 3)"
|
||||
>审核通过</el-button
|
||||
>
|
||||
<el-button type="danger" :disabled="row.status !== '1'" @click="handleAudit(row, 4)"
|
||||
>审核驳回</el-button
|
||||
>
|
||||
</template>
|
||||
<!-- <template #operation="{ row }">-->
|
||||
<!-- <el-button type="primary" :disabled="row.status !== '1'" @click="handleAudit(row, 3)"-->
|
||||
<!-- >审核通过</el-button-->
|
||||
<!-- >-->
|
||||
<!-- <el-button type="danger" :disabled="row.status !== '1'" @click="handleAudit(row, 4)"-->
|
||||
<!-- >审核驳回</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </template>-->
|
||||
</OrderRechangeTable>
|
||||
|
||||
<!-- 分页区域:使用接口返回的 total / current_page / per_page -->
|
||||
|
|
|
|||
|
|
@ -55,6 +55,6 @@ export const tableColumns = [
|
|||
{ prop: 'statusText', label: '状态', align: 'center' as const },
|
||||
{ prop: 'rechangeTime', label: '充值时间', align: 'center' as const },
|
||||
{ prop: 'rechangeAccount', label: '充值账号', align: 'center' as const },
|
||||
{ label: '操作', width: '240px', align: 'center' as const, slotName: 'operation' },
|
||||
// { label: '操作', width: '240px', align: 'center' as const, slotName: 'operation' },
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ const getCustomerList = async () => {
|
|||
const data: any = await getAgentListApi(params)
|
||||
|
||||
tableTree.value = data.data.map((item: any) => ({
|
||||
...item,
|
||||
accountName: item.username,
|
||||
userId: item.id,
|
||||
status: item.status === 1 ? '正常' : '禁用',
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export const search = [
|
|||
label: '账号名称',
|
||||
type: 'input' as const,
|
||||
placeholder: '请输入账号名称',
|
||||
width: '150px',
|
||||
width: '200px',
|
||||
},
|
||||
// 开始时间
|
||||
{
|
||||
|
|
@ -14,6 +14,7 @@ export const search = [
|
|||
type: 'date' as const,
|
||||
dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
width: '240px',
|
||||
},
|
||||
// 结束时间
|
||||
{
|
||||
|
|
@ -22,28 +23,30 @@ export const search = [
|
|||
type: 'date' as const,
|
||||
dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
width: '240px',
|
||||
},
|
||||
]
|
||||
|
||||
export const tableColumns = [
|
||||
// 账号名称
|
||||
{ label: '账号名称', prop: 'accountName'},
|
||||
// 账号id
|
||||
{ prop: 'userId', label: '账号id' },
|
||||
// 状态
|
||||
{ prop: 'status', label: '状态' },
|
||||
// 账号角色
|
||||
{ prop: 'role', label: '账号角色' },
|
||||
// 账号数量
|
||||
{ prop: 'accountQty', label: '账号数量' },
|
||||
// 点差分配比例
|
||||
{ prop: 'marginRatio', label: '点差分配比例', slotName: 'marginRatio' },
|
||||
// 手续费分成比例
|
||||
{ prop: 'commissionRatio', label: '手续费分成比例', slotName: 'commissionRatio' },
|
||||
// 注册时间
|
||||
{ prop: 'createTime', label: '注册时间', sortable: true },
|
||||
// 操作
|
||||
// { label: '操作', slotName: 'action' }
|
||||
// 账号名称
|
||||
{ label: '账号名称', prop: 'accountName' },
|
||||
// 账号id
|
||||
{ prop: 'userId', label: '账号id' },
|
||||
// 状态
|
||||
{ prop: 'status', label: '状态' },
|
||||
// 账号角色
|
||||
{ prop: 'role', label: '账号角色' },
|
||||
// 账号数量
|
||||
{ prop: 'accountQty', label: '账号数量' },
|
||||
{ prop: 'wallet_capital.amount', label: '资金', align: 'center' as const },
|
||||
// 点差分配比例
|
||||
{ prop: 'marginRatio', label: '点差分配比例', slotName: 'marginRatio' },
|
||||
// 手续费分成比例
|
||||
{ prop: 'commissionRatio', label: '手续费分成比例', slotName: 'commissionRatio' },
|
||||
// 注册时间
|
||||
{ prop: 'createTime', label: '注册时间', sortable: true },
|
||||
// 操作
|
||||
// { label: '操作', slotName: 'action' }
|
||||
]
|
||||
|
||||
// 点差表格配置
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
@reset="handleReset"
|
||||
>
|
||||
<template #button="{ form }">
|
||||
<el-button type="primary" @click="handleAddMarket()" v-auth="'agent_createAgen'">
|
||||
<el-button type="primary" @click="handleAddMarket()" v-auth="'agent_createAgent'">
|
||||
添加
|
||||
</el-button>
|
||||
<el-button
|
||||
|
|
|
|||
|
|
@ -50,12 +50,13 @@ export const clientSearch = [
|
|||
|
||||
//定义客户table列配置
|
||||
export const clientTableColumns = [
|
||||
{ prop: 'id', label: 'ID', align: 'center' as const },
|
||||
{ prop: 'username', label: '用户名', align: 'center' as const },
|
||||
{ prop: 'createdTime', label: '注册时间', align: 'center' as const },
|
||||
{ prop: 'agentUsername', label: '所属代理', align: 'center' as const },
|
||||
{ label: '状态', slotName: 'status', align: 'center' as const },
|
||||
{ label: '操作', slotName: 'action', align: 'center' as const }
|
||||
{ prop: 'id', label: 'ID', align: 'center' as const },
|
||||
{ prop: 'username', label: '用户名', align: 'center' as const },
|
||||
{ prop: 'createdTime', label: '注册时间', align: 'center' as const },
|
||||
{ prop: 'agentUsername', label: '所属代理', align: 'center' as const },
|
||||
{ prop: 'wallet_capital.amount', label: '资金', align: 'center' as const },
|
||||
{ label: '状态', slotName: 'status', align: 'center' as const },
|
||||
{ label: '操作', slotName: 'action', align: 'center' as const },
|
||||
]
|
||||
|
||||
//定义添加客户form配置
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ const menuFormRef = ref<FormInstance>()
|
|||
const menuFormRules = rules(menuForm.value, menuiconOptions)
|
||||
// icon和菜单表单选项映射
|
||||
const menuFormOptionsMap = ref({
|
||||
parentName: [] as any[],
|
||||
parent_id: [] as any[],
|
||||
icon: menuiconOptions,
|
||||
type: [
|
||||
{ label: '菜单', value: 1 },
|
||||
|
|
@ -142,7 +142,7 @@ const fetchMenuList = async () => {
|
|||
label: item.name,
|
||||
value: item.id ?? '',
|
||||
}))
|
||||
menuFormOptionsMap.value.parentName = [{ label: '一级菜单', value: '0' }, ...parentNameOptions]
|
||||
menuFormOptionsMap.value.parent_id = [{ label: '一级菜单', value: '0' }, ...parentNameOptions]
|
||||
} catch (err) {
|
||||
console.error('获取菜单列表失败', err)
|
||||
}
|
||||
|
|
@ -187,7 +187,7 @@ const handleSubmit = async () => {
|
|||
if (dialogType.value === 'add') {
|
||||
const params = {
|
||||
name: menuForm.value.name, // 菜单名称
|
||||
parent_id: menuForm.value.parentName, // 上级菜单id
|
||||
parent_id: menuForm.value.parent_id, // 上级菜单id
|
||||
path: menuForm.value.path, // 路由路径
|
||||
api: menuForm.value.api, // 后端路由
|
||||
icon: menuForm.value.icon, // 图标名称
|
||||
|
|
@ -213,6 +213,7 @@ const handleCancel = () => {
|
|||
menuForm.value = {
|
||||
name: '', // 菜单名称
|
||||
parentName: '', // 上级菜单名称
|
||||
parent_id: '', // 上级菜单名称
|
||||
path: '', // 路由路径
|
||||
api: '', // 后端路由
|
||||
icon: '', // 图标名称
|
||||
|
|
@ -227,6 +228,7 @@ const handleClose = () => {
|
|||
menuForm.value = {
|
||||
name: '', // 菜单名称
|
||||
parentName: '', // 上级菜单名称
|
||||
parent_id: '', // 上级菜单名称
|
||||
path: '', // 路由路径
|
||||
api: '', // 后端路由
|
||||
icon: '', // 图标名称
|
||||
|
|
|
|||
|
|
@ -37,12 +37,17 @@ export const menuTableColumns = [
|
|||
|
||||
//定义menuForm配置
|
||||
export const menuFormItemOptions = [
|
||||
{ prop: 'name', label: '菜单名称', type: 'input' as const,placeholder: '请输入菜单名称' },
|
||||
{ prop: 'parentName', label: '父级菜单', type: 'select' as const, placeholder: '请选择父级菜单' },
|
||||
{ prop: 'path', label: '前端路由', type: 'input' as const, placeholder: '请输入前端路由路径' },
|
||||
{ prop: 'api', label: '后端路由', type: 'input' as const, placeholder: '请输入后端路由' },
|
||||
{ prop: 'icon', label: '图标名称', type: 'select' as const, placeholder: '请选择图标名称' },
|
||||
{ prop: 'sort', label: '排序', type: 'number' as const, placeholder: '请输入排序,数字越小越靠前' },
|
||||
{ prop: 'type', label: '菜单类型', type: 'radio' as const, placeholder: '请选择菜单类型' },
|
||||
{ prop: 'status', label: '状态', type: 'radio' as const, placeholder: '请选择状态' },
|
||||
{ prop: 'name', label: '菜单名称', type: 'input' as const, placeholder: '请输入菜单名称' },
|
||||
{ prop: 'parent_id', label: '父级菜单', type: 'select' as const, placeholder: '请选择父级菜单' },
|
||||
{ prop: 'path', label: '前端路由', type: 'input' as const, placeholder: '请输入前端路由路径' },
|
||||
{ prop: 'api', label: '后端路由', type: 'input' as const, placeholder: '请输入后端路由' },
|
||||
{ prop: 'icon', label: '图标名称', type: 'select' as const, placeholder: '请选择图标名称' },
|
||||
{
|
||||
prop: 'sort',
|
||||
label: '排序',
|
||||
type: 'number' as const,
|
||||
placeholder: '请输入排序,数字越小越靠前',
|
||||
},
|
||||
{ prop: 'type', label: '菜单类型', type: 'radio' as const, placeholder: '请选择菜单类型' },
|
||||
{ prop: 'status', label: '状态', type: 'radio' as const, placeholder: '请选择状态' },
|
||||
]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export const search = [
|
|||
label: '公告名称',
|
||||
type: 'input' as const,
|
||||
placeholder: '请输入公告名称',
|
||||
width: '120px',
|
||||
width: '220px',
|
||||
},
|
||||
{
|
||||
prop: 'startDateTime',
|
||||
|
|
@ -15,7 +15,7 @@ export const search = [
|
|||
type: 'date' as const,
|
||||
dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
width: '180px',
|
||||
width: '220px',
|
||||
},
|
||||
{
|
||||
prop: 'endDateTime',
|
||||
|
|
@ -23,7 +23,7 @@ export const search = [
|
|||
type: 'date' as const,
|
||||
dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
width: '180px',
|
||||
width: '220px',
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
|
|
@ -34,6 +34,7 @@ export const search = [
|
|||
{ label: '草稿', value: 1 },
|
||||
{ label: '已发布', value: 2 },
|
||||
],
|
||||
width: '220px',
|
||||
},
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
type="primary"
|
||||
:disabled="!selectedRow"
|
||||
@click="handleEdit()"
|
||||
v-auth="'contracVarietediariety'"
|
||||
v-auth="'contractVariety_editVariety'"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
|
|
@ -57,11 +57,13 @@
|
|||
>
|
||||
<template #upload="{ formData }">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
v-model:file-list="fileList"
|
||||
class="upload-demo"
|
||||
:http-request="handleUpload"
|
||||
:before-upload="beforeUpload"
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
>
|
||||
<el-button type="primary">点击上传</el-button>
|
||||
<template #tip>
|
||||
|
|
@ -287,6 +289,19 @@ const handleReset = () => {
|
|||
const handleEdit = () => {
|
||||
getTradeGroupList()
|
||||
const row = selectedRow.value
|
||||
|
||||
if (row.image) {
|
||||
fileList.value = [
|
||||
{
|
||||
name: row.image.split('/').pop() || 'existing.jpg',
|
||||
url: row.image,
|
||||
status: 'success',
|
||||
},
|
||||
]
|
||||
} else {
|
||||
fileList.value = []
|
||||
}
|
||||
|
||||
varietyForm.value = {
|
||||
...row,
|
||||
id: row.id,
|
||||
|
|
@ -367,6 +382,21 @@ const handleUpload = async (options: any) => {
|
|||
}
|
||||
}
|
||||
|
||||
const uploadRef = ref()
|
||||
const handleExceed = (files: File[]) => {
|
||||
// 先清空已有文件列表
|
||||
if (uploadRef.value) {
|
||||
uploadRef.value.clearFiles()
|
||||
}
|
||||
// 手动触发新文件的上传
|
||||
const file = files[0]
|
||||
if (file) {
|
||||
uploadRef.value?.handleStart(file) // 手动加入文件队列
|
||||
// 手动调用上传(因为 http-request 是自定义的)
|
||||
handleUpload({ file, onSuccess: () => {}, onError: () => {} })
|
||||
}
|
||||
}
|
||||
|
||||
// 上传前校验:格式 + 大小(20KB = 20 * 1024)
|
||||
const beforeUpload = (file: File) => {
|
||||
// 严格校验后缀名
|
||||
|
|
@ -446,6 +476,7 @@ const handleCancel = () => {
|
|||
dialogVisible.value = false
|
||||
}
|
||||
const handleClose = () => {
|
||||
fileList.value = []
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ const handleInput = (index: number, val: string) => {
|
|||
|
||||
const handleFocus = (index: number) => {
|
||||
// 聚焦时清空当前输入框(可选:如果不需要清空可注释)
|
||||
inputList[index] = '';
|
||||
// inputList[index] = '';
|
||||
}
|
||||
|
||||
// 修复:删除键逻辑,确保删除后同步值
|
||||
|
|
|
|||
Loading…
Reference in New Issue