2025-06-03 09:46:52 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<el-drawer v-model="dialogStatus" :close-on-click-modal="false" size="65%"
|
|
|
|
|
|
@close="dialogOfClosedMethods(false)">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<h4>{{ title }}</h4>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template #default>
|
|
|
|
|
|
<div class="queryForm">
|
|
|
|
|
|
<el-form :model="form" ref="formRef" :inline="true" label-width="68px">
|
|
|
|
|
|
<el-form-item label="凭证类型">
|
2025-06-11 15:16:44 +08:00
|
|
|
|
<el-select v-model="form.voucherType" style="width: 200px" @change="handleChangeType">
|
2025-06-03 09:46:52 +08:00
|
|
|
|
<el-option v-for="item in voucherTypes" :label="item.label" :value="item.value"/>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="凭证字">
|
|
|
|
|
|
<el-select v-model="form.wordHead" style="width: 200px" disabled>
|
|
|
|
|
|
<el-option v-for="item in voucherTypes" :label="item.label" :value="item.value"/>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
<el-table v-loading="loading" :data="dataList" border>
|
|
|
|
|
|
<el-table-column prop="summary" label="摘要" align="left" min-width="90"
|
|
|
|
|
|
:show-overflow-tooltip="true">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input v-model="scope.row.summary" style="width: 100%"></el-input>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="direction" label="借/贷" align="center" min-width="40">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-select v-model="scope.row.direction" style="width: 100%">
|
|
|
|
|
|
<el-option v-for="item in salary_directions" :label="item.label" :value="item.value"/>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="subjectName" label="科目" align="left" min-width="110" :show-overflow-tooltip="true">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-cascader
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
filterable
|
2025-06-10 15:46:58 +08:00
|
|
|
|
v-model="scope.row.subjectCode"
|
2025-06-03 09:46:52 +08:00
|
|
|
|
:options="deptOptions"
|
|
|
|
|
|
:props="defaultProps"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="selectedValue" label="取值" align="center" min-width="60"
|
|
|
|
|
|
:show-overflow-tooltip="true">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-select v-model="scope.row.selectedValue" style="width: 100%">
|
2025-06-11 15:16:44 +08:00
|
|
|
|
<el-option v-for="item in salaryValuesList" :label="item.label" :value="item.value"/>
|
2025-06-03 09:46:52 +08:00
|
|
|
|
</el-select>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="操作" align="center" header-align="center" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<div >
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<el-tooltip content="新增">
|
|
|
|
|
|
<el-button type="primary"
|
|
|
|
|
|
link @click="handleAdd()" icon="Plus"></el-button>
|
|
|
|
|
|
</el-tooltip>
|
|
|
|
|
|
<el-tooltip content="移除" v-if="dataList.length > 1">
|
|
|
|
|
|
<el-button type="primary"
|
|
|
|
|
|
link @click="handleDel(scope.$index)" icon="Delete"></el-button>
|
|
|
|
|
|
</el-tooltip>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<div style="flex: auto">
|
|
|
|
|
|
<el-button @click="dialogOfClosedMethods(false)">{{ t('org.cancel') }}</el-button>
|
|
|
|
|
|
<el-button type="primary" @click="submitForm">{{ t('org.confirm') }}</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-drawer>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import {useI18n} from "vue-i18n";
|
|
|
|
|
|
import {getCurrentInstance, reactive, ref, toRefs, watch} from "vue"
|
|
|
|
|
|
import {addRule, getById, updateRule} from "@/api/system/hr/voucher-rule";
|
|
|
|
|
|
import {ElForm} from "element-plus";
|
|
|
|
|
|
import {delConfigBalanceSheet} from "@/api/system/standard/standard-statement-balance-sheet";
|
|
|
|
|
|
import modal from "@/plugins/modal";
|
|
|
|
|
|
const {t} = useI18n()
|
|
|
|
|
|
const {proxy} = getCurrentInstance()!;
|
|
|
|
|
|
|
2025-06-11 15:16:44 +08:00
|
|
|
|
const {salary_values, salary_directions, labor_fee_values}
|
|
|
|
|
|
= proxy?.useDict( "salary_values", "salary_directions", "labor_fee_values");
|
2025-06-03 09:46:52 +08:00
|
|
|
|
const emit: any = defineEmits(['dialogOfClosedMethods'])
|
|
|
|
|
|
const formRef = ref<InstanceType<typeof ElForm> | null>(null);
|
2025-06-11 15:16:44 +08:00
|
|
|
|
interface SalaryValueItem {
|
|
|
|
|
|
label: string
|
|
|
|
|
|
value: string | number
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const salaryValuesList = ref<SalaryValueItem[]>([])
|
|
|
|
|
|
|
2025-06-03 09:46:52 +08:00
|
|
|
|
const props: any = defineProps({
|
|
|
|
|
|
title: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: ""
|
|
|
|
|
|
},
|
|
|
|
|
|
open: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
|
|
|
|
|
},
|
|
|
|
|
|
deptOptions: {
|
|
|
|
|
|
type: Array,
|
|
|
|
|
|
default: [],
|
|
|
|
|
|
},
|
|
|
|
|
|
voucherTypes: {
|
|
|
|
|
|
type: Array<any>,
|
|
|
|
|
|
default: [],
|
|
|
|
|
|
},
|
|
|
|
|
|
wordHeads: {
|
|
|
|
|
|
type: Array<any>,
|
|
|
|
|
|
default: []
|
|
|
|
|
|
},
|
|
|
|
|
|
formId: {
|
|
|
|
|
|
default: undefined
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
const defaultProps: any = ref({
|
|
|
|
|
|
expandTrigger: 'hover',
|
|
|
|
|
|
label: 'name',
|
2025-06-10 15:46:58 +08:00
|
|
|
|
value: 'code',
|
2025-06-03 09:46:52 +08:00
|
|
|
|
children: 'children',
|
|
|
|
|
|
checkStrictly: false,
|
|
|
|
|
|
emitPath: false,
|
|
|
|
|
|
defaultExpandAll: true,
|
|
|
|
|
|
showAllLevels: false,
|
|
|
|
|
|
clearable: false,
|
|
|
|
|
|
filterable: true
|
|
|
|
|
|
})
|
|
|
|
|
|
const data: any = reactive({
|
|
|
|
|
|
form: {
|
|
|
|
|
|
voucherType: 0,
|
|
|
|
|
|
wordHead: '记'
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const {form} = toRefs(data);
|
|
|
|
|
|
const dialogStatus: any = ref(false);
|
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
|
// 1. 首先,为数据项定义一个明确的接口类型
|
|
|
|
|
|
interface VoucherItem {
|
|
|
|
|
|
id: null;
|
|
|
|
|
|
summary: string;
|
|
|
|
|
|
direction: string;
|
2025-06-10 15:46:58 +08:00
|
|
|
|
subjectCode: string | null;
|
2025-06-03 09:46:52 +08:00
|
|
|
|
selectedValue: string;
|
|
|
|
|
|
// 其他可能的字段...
|
|
|
|
|
|
[key: string]: any; // 这允许添加其他可能从后端返回的字段
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 为dataList提供正确的类型
|
|
|
|
|
|
const dataList = ref<VoucherItem[]>([]);
|
|
|
|
|
|
const typeTextMap: Record<number, string> = {
|
|
|
|
|
|
0: "计提{yy}年{mm}月工资",
|
|
|
|
|
|
1: "发放{yy}年{mm}月工资",
|
|
|
|
|
|
2: "收票{yy}年{mm}月兼职人员工资",
|
|
|
|
|
|
3: "发放{yy}年{mm}月兼职人员工资"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => props.open,
|
|
|
|
|
|
(val: any) => {
|
|
|
|
|
|
if (val) {
|
|
|
|
|
|
dialogStatus.value = props.open;
|
|
|
|
|
|
if (props.formId) {
|
|
|
|
|
|
getById(props.formId).then((res: any) => {
|
|
|
|
|
|
form.value = res.data;
|
|
|
|
|
|
dataList.value = res.data.employeeSalaryVoucherRules;
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
reset();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
reset();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{immediate: true}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/** 重置操作表单 */
|
|
|
|
|
|
function reset(): any {
|
|
|
|
|
|
form.value = {
|
|
|
|
|
|
voucherType: 0,
|
|
|
|
|
|
wordHead: '记'
|
2025-06-11 15:16:44 +08:00
|
|
|
|
}
|
2025-06-03 09:46:52 +08:00
|
|
|
|
|
2025-06-11 15:16:44 +08:00
|
|
|
|
// 先根据 voucherType 给 salaryValuesList 赋值
|
|
|
|
|
|
if (form.value.voucherType === 0 || form.value.voucherType === 1) {
|
|
|
|
|
|
salaryValuesList.value = salary_values.value
|
|
|
|
|
|
} else {
|
|
|
|
|
|
salaryValuesList.value = labor_fee_values.value
|
|
|
|
|
|
}
|
2025-06-03 09:46:52 +08:00
|
|
|
|
|
2025-06-11 15:16:44 +08:00
|
|
|
|
// 取第一个值
|
|
|
|
|
|
const selectedValue = salaryValuesList.value.length > 0 ? salaryValuesList.value[0].value : null
|
2025-06-03 09:46:52 +08:00
|
|
|
|
|
2025-06-11 15:16:44 +08:00
|
|
|
|
// 设置 dataList
|
|
|
|
|
|
const summaryTemplate = typeTextMap[form.value.voucherType] || ""
|
|
|
|
|
|
|
|
|
|
|
|
dataList.value = [
|
|
|
|
|
|
{
|
|
|
|
|
|
id: null,
|
|
|
|
|
|
summary: summaryTemplate,
|
|
|
|
|
|
direction: "1",
|
|
|
|
|
|
subjectCode: props.deptOptions?.[0]?.code || null,
|
|
|
|
|
|
selectedValue: selectedValue,
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
formRef?.value?.resetFields()
|
2025-06-03 09:46:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-06-11 15:16:44 +08:00
|
|
|
|
function addRecord() {
|
2025-06-03 09:46:52 +08:00
|
|
|
|
const summaryTemplate = typeTextMap[form.value.voucherType] || "";
|
|
|
|
|
|
|
2025-06-11 15:16:44 +08:00
|
|
|
|
// 根据 voucherType 先切换数据源
|
|
|
|
|
|
if (form.value.voucherType === 0 || form.value.voucherType === 1) {
|
|
|
|
|
|
salaryValuesList.value = salary_values.value;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
salaryValuesList.value = labor_fee_values.value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果 salaryValuesList 为空,安全处理(防止访问 undefined)
|
|
|
|
|
|
const selectedValue = salaryValuesList.value.length > 0 ? salaryValuesList.value[0].value : null;
|
|
|
|
|
|
|
|
|
|
|
|
// 新增一条记录
|
2025-06-03 09:46:52 +08:00
|
|
|
|
dataList.value.push({
|
|
|
|
|
|
id: null,
|
|
|
|
|
|
summary: summaryTemplate,
|
|
|
|
|
|
direction: "1",
|
2025-06-10 15:46:58 +08:00
|
|
|
|
subjectCode: props.deptOptions?.[0]?.code || null,
|
2025-06-11 15:16:44 +08:00
|
|
|
|
selectedValue: selectedValue,
|
2025-06-03 09:46:52 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-11 15:16:44 +08:00
|
|
|
|
function handleChangeType() {
|
|
|
|
|
|
// 根据 voucherType 先切换数据源
|
|
|
|
|
|
if (form.value.voucherType === 0 || form.value.voucherType === 1) {
|
|
|
|
|
|
salaryValuesList.value = salary_values.value;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
salaryValuesList.value = labor_fee_values.value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-06-03 09:46:52 +08:00
|
|
|
|
|
|
|
|
|
|
function dialogOfClosedMethods(val: any): any {
|
|
|
|
|
|
dialogStatus.value = false;
|
|
|
|
|
|
emit('dialogOfClosedMethods', val);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function submitForm() {
|
|
|
|
|
|
if (dataList.value.length < 2) {
|
|
|
|
|
|
modal.msgWarning("请至少录入两条数据!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否至少有一贷一借
|
|
|
|
|
|
const hasDebit = dataList.value.some((item: any) => item.direction == '1');
|
|
|
|
|
|
const hasCredit = dataList.value.some((item: any) => item.direction == '2');
|
|
|
|
|
|
|
|
|
|
|
|
if (!hasDebit || !hasCredit) {
|
|
|
|
|
|
modal.msgWarning("请至少录入一条借方和一条贷方数据!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const dataSave = {
|
|
|
|
|
|
...form.value,
|
|
|
|
|
|
salaryTemplateDetailDtos: dataList.value
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (props.formId) {
|
|
|
|
|
|
//修改
|
|
|
|
|
|
updateRule(dataSave).then((response: any) => {
|
|
|
|
|
|
if (response.code === 0) {
|
|
|
|
|
|
modal.msgSuccess("修改成功")
|
|
|
|
|
|
dialogOfClosedMethods(true);
|
|
|
|
|
|
reset();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
modal.msgError(response.message)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
addRule(dataSave).then((response: any) => {
|
|
|
|
|
|
if (response.code === 0) {
|
|
|
|
|
|
modal.msgSuccess("新增成功")
|
|
|
|
|
|
dialogOfClosedMethods(true);
|
|
|
|
|
|
reset();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
modal.msgError(response.message)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleAdd() {
|
|
|
|
|
|
addRecord();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleDel(index: any) {
|
|
|
|
|
|
dataList.value.splice(index, 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|