This commit is contained in:
mazh 2026-04-25 20:50:57 +08:00
commit a6301e13d8
4 changed files with 481 additions and 108 deletions

View File

@ -0,0 +1,22 @@
import { request } from '@/api'
//获取手续费模板
export const getFeeSettingList = () => {
return request.get('/feeHandl/getFeeSettingList')
}
//获取手续费模板详情
export const getFeeSettingDetail = (params: any) => {
return request.get('/feeHandl/getFeeSettingDetail', { ...params })
}
//创建手续费模板
export const createFeeSetting = (params: any) => {
return request.post('/feeHandl/createFeeSetting', { ...params })
}
//编辑手续费模板
export const editFeeSetting = (params: any) => {
return request.post('/feeHandl/editFeeSetting', { ...params })
}
//设置手续费模板详情
export const setFeeSettingDetail = (params: any) => {
return request.post('/feeHandl/setFeeSettingDetail', { ...params })
}

View File

@ -1,76 +1,140 @@
<template>
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-bind="$attrs">
<!-- 动态表单项 -->
<el-row :gutter="props.rowGutter || 0">
<template v-for="(item, index) in formItems" :key="index">
<el-col :span="props.colSpan || 24">
<el-form-item :label="item.label" :prop="item.prop" :required="item.required" :label-position="item.labelPosition || 'left'"
:label-width="item.labelWidth || '125px'" :class="item.class">
<!-- 输入框 -->
<el-input v-if="item.type === 'input'" v-model="formData[item.prop]"
:placeholder="item.placeholder" :disabled="item.disabled" clearable />
<!-- 密码输入框 -->
<el-input v-else-if="item.type === 'password'" v-model="formData[item.prop]"
:placeholder="item.placeholder" :disabled="item.disabled" clearable show-password type="password" />
<!-- 下拉选择框 -->
<el-select v-else-if="item.type === 'select'" v-model="formData[item.prop]"
:placeholder="item.placeholder" :disabled="item.disabled" clearable style="width: 100%"
@change="handleItemChange(item.prop, formData[item.prop])">
<el-option v-for="option in props.optionsMap?.[item.prop] || []" :key="option.value"
:label="option.label" :value="option.value">
<template v-if="option.icon" #label>
<span style="display: flex; align-items: center; gap: 8px;">
<el-icon v-if="option.icon">
<component :is="option.icon" />
</el-icon>
<span>{{ option.label }}</span>
</span>
</template>
</el-option>
</el-select>
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-bind="$attrs">
<!-- 动态表单项 -->
<el-row :gutter="props.rowGutter || 0">
<template v-for="(item, index) in formItems" :key="index">
<el-col :span="props.colSpan || 24">
<el-form-item
:label="item.label"
:prop="item.prop"
:required="item.required"
:label-position="item.labelPosition || 'left'"
:label-width="item.labelWidth || '125px'"
:class="item.class"
>
<!-- 输入框 -->
<el-input
v-if="item.type === 'input'"
v-model="formData[item.prop]"
:placeholder="item.placeholder"
:disabled="item.disabled"
clearable
/>
<!-- 密码输入框 -->
<el-input
v-else-if="item.type === 'password'"
v-model="formData[item.prop]"
:placeholder="item.placeholder"
:disabled="item.disabled"
clearable
show-password
type="password"
/>
<!-- 密码输入框 -->
<el-input
v-else-if="item.type === 'textarea'"
v-model="formData[item.prop]"
:placeholder="item.placeholder"
:disabled="item.disabled"
clearable
show-password
type="textarea"
/>
<!-- 下拉选择框 -->
<el-select
v-else-if="item.type === 'select'"
v-model="formData[item.prop]"
:placeholder="item.placeholder"
:disabled="item.disabled"
clearable
style="width: 100%"
@change="handleItemChange(item.prop, formData[item.prop])"
>
<el-option
v-for="option in props.optionsMap?.[item.prop] || []"
:key="option.value"
:label="option.label"
:value="option.value"
>
<template v-if="option.icon" #label>
<span style="display: flex; align-items: center; gap: 8px">
<el-icon v-if="option.icon">
<component :is="option.icon" />
</el-icon>
<span>{{ option.label }}</span>
</span>
</template>
</el-option>
</el-select>
<!-- 数字输入框 -->
<el-input-number v-else-if="item.type === 'number'" v-model="formData[item.prop]"
:min="item.min" :max="item.max" :placeholder="item.placeholder" :disabled="item.disabled"
style="width: 100%" />
<!-- 数字输入框 -->
<el-input-number
v-else-if="item.type === 'number'"
v-model="formData[item.prop]"
:min="item.min"
:max="item.max"
:placeholder="item.placeholder"
:disabled="item.disabled"
style="width: 100%"
/>
<!-- 单选框组 -->
<el-radio-group v-else-if="item.type === 'radio'" v-model="formData[item.prop]">
<el-radio v-for="option in props.optionsMap?.[item.prop] || []" :key="option.value"
:value="option.value">
{{ option.label }}
</el-radio>
</el-radio-group>
<!-- 单选框组 -->
<el-radio-group v-else-if="item.type === 'radio'" v-model="formData[item.prop]">
<el-radio
v-for="option in props.optionsMap?.[item.prop] || []"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</el-radio>
</el-radio-group>
<!-- 复选框组 -->
<el-checkbox-group v-else-if="item.type === 'checkbox'" v-model="formData[item.prop]">
<el-checkbox v-for="option in props.optionsMap?.[item.prop] || []" :key="option.value"
:value="option.value">
{{ option.label }}
</el-checkbox>
</el-checkbox-group>
<el-switch v-else-if="item.type === 'switch'" v-model="formData[item.prop]" :active-value="1"
:inactive-value="2" />
<!-- 日期选择器单个/范围 -->
<el-date-picker v-else-if="item.type === 'date'" v-model="formData[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-time-picker v-else-if="item.type === 'time'" v-model="formData[item.prop]"
:range-separator="item.rangeSeparator || '至'"
:start-placeholder="item.startPlaceholder || '开始时间'"
:end-placeholder="item.endPlaceholder || '结束时间'"
:value-format="item.valueFormat || 'HH:mm:ss'" :is-range="item.isRange ?? true" />
<!-- 自定义插槽 -->
<slot v-else :name="item.slotName" :formData="formData" />
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
<!-- 复选框组 -->
<el-checkbox-group v-else-if="item.type === 'checkbox'" v-model="formData[item.prop]">
<el-checkbox
v-for="option in props.optionsMap?.[item.prop] || []"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</el-checkbox>
</el-checkbox-group>
<el-switch
v-else-if="item.type === 'switch'"
v-model="formData[item.prop]"
:active-value="1"
:inactive-value="2"
/>
<!-- 日期选择器单个/范围 -->
<el-date-picker
v-else-if="item.type === 'date'"
v-model="formData[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-time-picker
v-else-if="item.type === 'time'"
v-model="formData[item.prop]"
:range-separator="item.rangeSeparator || '至'"
:start-placeholder="item.startPlaceholder || '开始时间'"
:end-placeholder="item.endPlaceholder || '结束时间'"
:value-format="item.valueFormat || 'HH:mm:ss'"
:is-range="item.isRange ?? true"
/>
<!-- 自定义插槽 -->
<slot v-else :name="item.slotName" :formData="formData" />
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
</template>
<script setup lang="ts">
@ -78,40 +142,55 @@ import type { FormInstance, FormRules } from 'element-plus'
import type { Component } from 'vue'
interface FormItem {
type: 'input' | 'select' | 'number' | 'radio' | 'slot' | 'checkbox' | 'date' | 'switch' | 'edit' | 'password' | 'time' | 'upload'
label: string
prop: string
placeholder?: string
required?: boolean
disabled?: boolean
min?: number
max?: number
slotName?: string //
labelPosition?: 'left' | 'right' | 'top'
labelWidth?: string
class?: string
dateType?: 'date' | 'daterange' | 'monthrange' | 'yearrange' | 'datetimerange'
timeType?: 'time' | 'timerange'
rangeSeparator?: string
startPlaceholder?: string
endPlaceholder?: string
valueFormat?: string
clearable?: boolean
disabledDate?: (time: Date) => boolean
isRange?: boolean
type:
| 'input'
| 'select'
| 'number'
| 'radio'
| 'slot'
| 'checkbox'
| 'date'
| 'switch'
| 'edit'
| 'password'
| 'time'
| 'upload'
label: string
prop: string
placeholder?: string
required?: boolean
disabled?: boolean
min?: number
max?: number
slotName?: string //
labelPosition?: 'left' | 'right' | 'top'
labelWidth?: string
class?: string
dateType?: 'date' | 'daterange' | 'monthrange' | 'yearrange' | 'datetimerange'
timeType?: 'time' | 'timerange'
rangeSeparator?: string
startPlaceholder?: string
endPlaceholder?: string
valueFormat?: string
clearable?: boolean
disabledDate?: (time: Date) => boolean
isRange?: boolean
}
interface Props {
formData: Record<string, any>
formRules: FormRules
formItems: FormItem[]
optionsMap?: Record<string, Array<{
label: string | undefined
value: string | number
icon?: Component
}>>
rowGutter?: number // 0
colSpan?: number // 24
formData: Record<string, any>
formRules: FormRules
formItems: FormItem[]
optionsMap?: Record<
string,
Array<{
label: string | undefined
value: string | number
icon?: Component
}>
>
rowGutter?: number // 0
colSpan?: number // 24
}
const formRef = ref<FormInstance>()
@ -119,11 +198,11 @@ const props = defineProps<Props>()
const emit = defineEmits(['form-item-change'])
const handleItemChange = (field: string, value: any) => {
emit('form-item-change', field, value)
emit('form-item-change', field, value)
}
//
defineExpose({
validate: () => formRef.value?.validate(),
resetFields: () => formRef.value?.resetFields()
validate: () => formRef.value?.validate(),
resetFields: () => formRef.value?.resetFields(),
})
</script>
</script>

View File

@ -1,7 +1,248 @@
<script setup lang="ts"></script>
<template>
<h1>手续费模板</h1>
<div class="mould-fee">
<header>
<div class="header-actions">
<el-button type="primary" @click="addFee">添加模板</el-button>
<el-button type="primary" @click="editFee">编辑模板</el-button>
<el-button type="primary" @click="changeStatus(1)">启用模板</el-button>
<el-button type="danger" @click="changeStatus(2)">禁用模板</el-button>
<el-button type="primary" @click="editFeeDetail">编辑模板详情</el-button>
</div>
</header>
<div class="table-container">
<div class="table-container-left">
<el-table
ref="singleTableRef"
height="100%"
:data="tableData"
highlight-current-row
border
@current-change="handleCurrentChange"
>
<el-table-column type="index" width="55" />
<el-table-column
v-for="column in tableColumns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
/>
</el-table>
</div>
<div class="table-container-right">
<el-table height="100%" :data="tableDataDetail">
<el-table-column
v-for="column in tableColumnsDetail"
:key="column.prop"
:prop="column.prop"
:label="column.label"
/>
</el-table>
</div>
</div>
<el-dialog
v-model="dialogVisible"
:title="dialogTitleType === 1 ? '添加手续费模板' : '编辑手续费模板'"
width="500"
>
<Form :formItems="formItems" :formRules="formRules" :formData="formData" />
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submit">确认</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="detaildialogVisible" title="编辑手续费模板详情" width="700">
<el-table height="600px" :data="tableDataDetail">
<template v-for="column in tableColumnsDetail" :key="column.prop">
<el-table-column v-if="column.prop === 'fee'" :prop="column.prop" :label="column.label">
<template #default="scope">
<el-input-number
:min="0"
:max="999999999"
:controls="false"
v-model="scope.row.fee"
/>
</template>
</el-table-column>
<el-table-column v-else :prop="column.prop" :label="column.label" />
</template>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button @click="detaildialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitDetail">确认</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<style scoped lang="scss"></style>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
import {
getFeeSettingList,
getFeeSettingDetail,
createFeeSetting,
editFeeSetting,
setFeeSettingDetail,
} from '@/api/modules/mould/handleFee.ts'
import Form from '@/components/common/Form.vue'
import { formDataList, formRulesList } from './option.ts'
const title = ref('手续费模板')
const buttons = ref([{ label: '新增', type: 'primary' as const, key: 'add' }])
const dialogVisible = ref(false)
const dialogTitleType = ref(1)
const formData = ref({
name: '',
status: 1,
type: 2,
description: '',
})
const formItems = ref(formDataList)
const formRules = ref(formRulesList)
const resetFormData = () => {
formData.value = {
name: '',
status: 1,
type: 2,
description: '',
}
}
const tableData = ref([])
const tableColumns = ref([
{ prop: 'name', label: '名称' },
{ prop: 'type', label: '状态' },
])
const currentRow = ref({})
const singleTableRef = ref()
const setCurrent = (row) => {
singleTableRef.value.setCurrentRow(row)
}
const handleCurrentChange = (row: any) => {
currentRow.value = row
getItemDetail(row.id)
}
const tableDataDetail = ref([])
const tableColumnsDetail = ref([
{ prop: 'name', label: '品种' },
{ prop: 'code', label: '编号' },
{ prop: 'fee', label: '开仓手续费' },
])
const getTableData = async () => {
const res = await getFeeSettingList()
const savedId = currentRow.value?.id
tableData.value = res
console.log(res)
if (res && res.length > 0) {
const targetRow = savedId ? res.find((item: any) => item.id === savedId) : null
if (targetRow) {
setCurrent(targetRow)
handleCurrentChange(targetRow)
} else {
setCurrent(res[0])
handleCurrentChange(res[0])
}
}
}
const getItemDetail = async (id: number) => {
const res = await getFeeSettingDetail({ id })
tableDataDetail.value = res
}
const addFee = () => {
dialogVisible.value = true
dialogTitleType.value = 1
resetFormData()
}
const editFee = () => {
dialogVisible.value = true
dialogTitleType.value = 2
formData.value = {
id: currentRow.value.id,
name: currentRow.value.name,
type: currentRow.value.type,
description: currentRow.value.description,
}
}
const changeStatus = (status: number) => {
dialogTitleType.value = 2
formData.value = {
id: currentRow.value.id,
name: currentRow.value.name,
type: currentRow.value.type,
description: currentRow.value.description,
status,
}
submit()
}
const submit = async () => {
console.log(formData.value)
if (dialogTitleType.value === 1) {
await createFeeSetting(formData.value)
} else {
await editFeeSetting(formData.value)
}
resetFormData()
dialogVisible.value = false
getTableData()
}
const detaildialogVisible = ref(false)
const editFeeDetail = () => {
detaildialogVisible.value = true
console.log(tableDataDetail.value)
}
const submitDetail = async () => {
let contents_json = {}
tableDataDetail.value.forEach((item) => {
contents_json[item.variety_id] = item.fee
})
await setFeeSettingDetail({
id: currentRow.value.id,
contents_json: JSON.stringify(contents_json),
})
detaildialogVisible.value = false
getTableData()
}
onMounted(() => {
getTableData()
})
</script>
<style scoped lang="scss">
.mould-fee {
height: 100%;
overflow: hidden;
}
header {
margin-bottom: 8px;
}
.table-container {
display: flex;
column-gap: 20px;
height: calc(100% - 40px);
.table-container-left {
width: 300px;
height: 100%;
flex: 0 0 auto;
overflow: hidden;
}
.table-container-right {
flex: 1;
height: 100%;
overflow: hidden;
}
}
</style>

View File

@ -0,0 +1,31 @@
export const formDataList = [
{
prop: 'name',
label: '名称',
type: 'input' as const,
placeholder: '请输入名称',
width: '300px',
},
{
prop: 'status',
label: '是否开启',
type: 'switch' as const,
},
{
prop: 'type',
label: '是否默认',
type: 'switch' as const,
},
{
prop: 'description',
label: '备注',
type: 'textarea' as const,
placeholder: '请输入备注',
width: '300px',
},
]
export const formRulesList = {
name: [{ required: true, message: '请输入名称', trigger: ['change'] }],
// type: [{ required: true, message: '请选择是否默认', trigger: ['change'] }],
description: [{ required: true, message: '请输入备注', trigger: ['change'] }],
}