| | |
| | | // 获取路由 |
| | | export const testUserList = () => { |
| | | return request({ |
| | | url: '/test/user/list', |
| | | url: '/system/user/listAll', |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | :row-key="rowKey" |
| | | style="width: 100%;" |
| | | > |
| | | <el-table-column v-if="showSelection" type="selection" width="55" align="center" /> |
| | | <el-table-column v-if="showIndex" label="序号" width="60" align="center" fixed="left"> |
| | | <el-table-column v-if="showSelection" type="selection" width="55" align="center" :show-overflow-tooltip="false" /> |
| | | <el-table-column v-if="showIndex" label="序号" width="60" align="center" fixed="left" :show-overflow-tooltip="false"> |
| | | <template #default="scope"> |
| | | {{ getRowIndex(scope.$index) }} |
| | | </template> |
| | |
| | | /** |
| | | * 创建删除功能 |
| | | * @param {Object} options 配置选项 |
| | | * @param {Function} options.deleteApi 删除API函数 |
| | | * @param {Function} options.getList 重新获取列表数据的函数 |
| | | * @param {Function|Function} options.deleteApi 删除API函数或返回API函数的函数 |
| | | * @param {Function|Function} options.getList 重新获取列表数据的函数或返回函数的函数 |
| | | * @param {Ref} options.selectedRows 选中行的响应式引用 |
| | | * @param {Ref} options.tableData 表格数据的响应式引用 |
| | | * @param {Ref} options.total 总数的响应式引用 |
| | |
| | | successText = "删除成功", |
| | | useLocalUpdate = false |
| | | } = options; |
| | | |
| | | /** |
| | | * 获取实际的删除API函数 |
| | | * 支持直接传入函数或返回函数的函数 |
| | | */ |
| | | const getDeleteApi = () => { |
| | | if (typeof deleteApi === 'function') { |
| | | // 尝试调用看是否返回函数 |
| | | try { |
| | | const result = deleteApi(); |
| | | return typeof result === 'function' ? result : deleteApi; |
| | | } catch (error) { |
| | | // 如果调用出错,说明这本身就是API函数 |
| | | return deleteApi; |
| | | } |
| | | } |
| | | return deleteApi; |
| | | }; |
| | | |
| | | /** |
| | | * 获取实际的获取列表函数 |
| | | * 支持直接传入函数或返回函数的函数 |
| | | */ |
| | | const getListFunction = () => { |
| | | if (typeof getList === 'function') { |
| | | try { |
| | | const result = getList(); |
| | | return typeof result === 'function' ? result : getList; |
| | | } catch (error) { |
| | | // 如果调用出错,说明这本身就是列表函数 |
| | | return getList; |
| | | } |
| | | } |
| | | return getList; |
| | | }; |
| | | |
| | | /** |
| | | * 批量删除方法 |
| | |
| | | |
| | | // 提取ID |
| | | const ids = rowsToDelete.map(item => item.id); |
| | | |
| | | // 获取当前的删除API函数 |
| | | const currentDeleteApi = getDeleteApi(); |
| | | if (!currentDeleteApi) { |
| | | ElMessage.error("删除API未配置"); |
| | | return false; |
| | | } |
| | | |
| | | // 调用删除API |
| | | const res = await deleteApi(ids); |
| | | const res = await currentDeleteApi(ids); |
| | | |
| | | if (res.code === 200) { |
| | | // 根据配置选择更新方式 |
| | |
| | | } |
| | | } else { |
| | | // 重新获取数据 |
| | | if (getList) { |
| | | await getList(); |
| | | const currentGetList = getListFunction(); |
| | | if (currentGetList) { |
| | | await currentGetList(); |
| | | } |
| | | } |
| | | |
| | |
| | | import { reactive } from "vue"; |
| | | /** |
| | | * 通用表单数据管理组合式函数 |
| | | * 提供表单数据的增删改查、验证、重置等功能 |
| | | */ |
| | | import { ref, reactive, computed, nextTick } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { clone } from "lodash"; |
| | | |
| | | /** |
| | | * 创建表单数据管理功能 |
| | | * @param {Object} options 配置选项 |
| | | * @param {Object} options.defaultForm 默认表单结构 |
| | | * @param {Function} options.addApi 新增API函数 |
| | | * @param {Function} options.updateApi 更新API函数 |
| | | * @param {Function} options.getDetailApi 获取详情API函数 |
| | | * @param {Object} options.rules 表单验证规则 |
| | | * @param {Function} options.beforeSubmit 提交前的数据处理函数 |
| | | * @param {Function} options.afterSubmit 提交后的回调函数 |
| | | * @param {Boolean} options.autoReset 提交成功后是否自动重置表单 |
| | | * @returns {Object} 返回表单管理相关的方法和状态 |
| | | */ |
| | | export function useFormData(options = {}) { |
| | | const { |
| | | defaultForm = {}, |
| | | addApi, |
| | | updateApi, |
| | | getDetailApi, |
| | | rules = {}, |
| | | beforeSubmit, |
| | | afterSubmit, |
| | | autoReset = true |
| | | } = options; |
| | | |
| | | export default function useFormData(initData) { |
| | | // 表单状态 |
| | | const form = ref({ ...defaultForm }); |
| | | const originalForm = ref({ ...defaultForm }); |
| | | const loading = ref(false); |
| | | const dialogVisible = ref(false); |
| | | const mode = ref('add'); // 'add', 'edit', 'view' |
| | | const title = ref(''); |
| | | const formRef = ref(null); |
| | | |
| | | // 计算属性 |
| | | const isAdd = computed(() => mode.value === 'add'); |
| | | const isEdit = computed(() => mode.value === 'edit'); |
| | | const isView = computed(() => mode.value === 'view'); |
| | | const isReadonly = computed(() => mode.value === 'view'); |
| | | const submitButtonText = computed(() => { |
| | | return isAdd.value ? '新增' : '保存'; |
| | | }); |
| | | |
| | | /** |
| | | * 打开表单对话框 |
| | | * @param {String} formMode 表单模式:'add', 'edit', 'view' |
| | | * @param {Object} data 编辑/查看时的数据 |
| | | * @param {String} customTitle 自定义标题 |
| | | */ |
| | | const openForm = async (formMode = 'add', data = null, customTitle = '') => { |
| | | mode.value = formMode; |
| | | |
| | | // 设置标题 |
| | | if (customTitle) { |
| | | title.value = customTitle; |
| | | } else { |
| | | const titleMap = { |
| | | add: '新增', |
| | | edit: '编辑', |
| | | view: '查看' |
| | | }; |
| | | title.value = titleMap[formMode] || '表单'; |
| | | } |
| | | |
| | | // 根据模式处理数据 |
| | | if (formMode === 'add') { |
| | | resetForm(); |
| | | } else if (data) { |
| | | // 编辑/查看模式,如果有详情API则获取最新数据 |
| | | if (getDetailApi && data.id) { |
| | | loading.value = true; |
| | | try { |
| | | const res = await getDetailApi(data.id); |
| | | if (res.code === 200) { |
| | | setFormData(res.data); |
| | | } else { |
| | | ElMessage.error('获取详情失败'); |
| | | setFormData(data); |
| | | } |
| | | } catch (error) { |
| | | console.error('获取详情失败:', error); |
| | | setFormData(data); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } else { |
| | | setFormData(data); |
| | | } |
| | | } |
| | | |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | /** |
| | | * 设置表单数据 |
| | | * @param {Object} data 表单数据 |
| | | */ |
| | | const setFormData = (data) => { |
| | | form.value = { ...defaultForm, ...data }; |
| | | originalForm.value = { ...form.value }; |
| | | }; |
| | | |
| | | /** |
| | | * 重置表单 |
| | | */ |
| | | const resetForm = () => { |
| | | form.value = { ...defaultForm }; |
| | | originalForm.value = { ...defaultForm }; |
| | | if (formRef.value) { |
| | | formRef.value.resetFields(); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 恢复表单到原始状态 |
| | | */ |
| | | const restoreForm = () => { |
| | | form.value = { ...originalForm.value }; |
| | | if (formRef.value) { |
| | | formRef.value.clearValidate(); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 表单验证 |
| | | * @returns {Promise<Boolean>} 验证结果 |
| | | */ |
| | | const validateForm = async () => { |
| | | if (!formRef.value) return true; |
| | | |
| | | try { |
| | | await formRef.value.validate(); |
| | | return true; |
| | | } catch (error) { |
| | | console.log('表单验证失败:', error); |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 提交表单 |
| | | * @param {Object} customData 自定义提交数据 |
| | | * @returns {Promise<Boolean>} 提交结果 |
| | | */ |
| | | const submitForm = async (customData = null) => { |
| | | // 验证表单 |
| | | const isValid = await validateForm(); |
| | | if (!isValid) { |
| | | ElMessage.warning('请检查表单数据'); |
| | | return false; |
| | | } |
| | | |
| | | // 准备提交数据 |
| | | let submitData = customData || { ...form.value }; |
| | | |
| | | // 执行提交前处理 |
| | | if (beforeSubmit && typeof beforeSubmit === 'function') { |
| | | try { |
| | | submitData = await beforeSubmit(submitData, mode.value); |
| | | } catch (error) { |
| | | console.error('提交前处理失败:', error); |
| | | ElMessage.error('数据处理失败'); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | loading.value = true; |
| | | |
| | | try { |
| | | let res; |
| | | |
| | | if (isAdd.value && addApi) { |
| | | res = await addApi(submitData); |
| | | } else if (isEdit.value && updateApi) { |
| | | res = await updateApi(submitData); |
| | | } else { |
| | | ElMessage.error('未配置相应的API接口'); |
| | | return false; |
| | | } |
| | | |
| | | if (res.code === 200) { |
| | | const action = isAdd.value ? '新增' : '更新'; |
| | | ElMessage.success(`${action}成功`); |
| | | |
| | | // 执行提交后回调 |
| | | if (afterSubmit && typeof afterSubmit === 'function') { |
| | | await afterSubmit(res.data, mode.value, submitData); |
| | | } |
| | | |
| | | // 自动重置表单 |
| | | if (autoReset) { |
| | | closeForm(); |
| | | } |
| | | |
| | | return true; |
| | | } else { |
| | | ElMessage.error(res.msg || '操作失败'); |
| | | return false; |
| | | } |
| | | } catch (error) { |
| | | console.error('提交失败:', error); |
| | | ElMessage.error('操作失败,请稍后重试'); |
| | | return false; |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 关闭表单对话框 |
| | | */ |
| | | const closeForm = () => { |
| | | dialogVisible.value = false; |
| | | resetForm(); |
| | | }; |
| | | |
| | | /** |
| | | * 检查表单是否有变更 |
| | | * @returns {Boolean} 是否有变更 |
| | | */ |
| | | const hasChanges = computed(() => { |
| | | return JSON.stringify(form.value) !== JSON.stringify(originalForm.value); |
| | | }); |
| | | |
| | | /** |
| | | * 带确认的关闭表单 |
| | | */ |
| | | const closeFormWithConfirm = async () => { |
| | | if (hasChanges.value && !isView.value) { |
| | | try { |
| | | await ElMessageBox.confirm('表单数据已修改,确定要离开吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | }); |
| | | closeForm(); |
| | | } catch { |
| | | // 用户取消 |
| | | } |
| | | } else { |
| | | closeForm(); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 设置表单字段值 |
| | | * @param {String} field 字段名 |
| | | * @param {Any} value 字段值 |
| | | */ |
| | | const setFieldValue = (field, value) => { |
| | | form.value[field] = value; |
| | | }; |
| | | |
| | | /** |
| | | * 获取表单字段值 |
| | | * @param {String} field 字段名 |
| | | * @returns {Any} 字段值 |
| | | */ |
| | | const getFieldValue = (field) => { |
| | | return form.value[field]; |
| | | }; |
| | | |
| | | /** |
| | | * 批量设置表单字段值 |
| | | * @param {Object} values 字段值对象 |
| | | */ |
| | | const setFieldValues = (values) => { |
| | | Object.keys(values).forEach(key => { |
| | | if (form.value.hasOwnProperty(key)) { |
| | | form.value[key] = values[key]; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 清除字段验证 |
| | | * @param {String|Array} fields 字段名或字段名数组 |
| | | */ |
| | | const clearValidate = (fields = null) => { |
| | | if (formRef.value) { |
| | | formRef.value.clearValidate(fields); |
| | | } |
| | | }; |
| | | |
| | | return { |
| | | // 状态 |
| | | form, |
| | | loading, |
| | | dialogVisible, |
| | | mode, |
| | | title, |
| | | formRef, |
| | | |
| | | // 计算属性 |
| | | isAdd, |
| | | isEdit, |
| | | isView, |
| | | isReadonly, |
| | | submitButtonText, |
| | | hasChanges, |
| | | |
| | | // 方法 |
| | | openForm, |
| | | setFormData, |
| | | resetForm, |
| | | restoreForm, |
| | | validateForm, |
| | | submitForm, |
| | | closeForm, |
| | | closeFormWithConfirm, |
| | | setFieldValue, |
| | | getFieldValue, |
| | | setFieldValues, |
| | | clearValidate |
| | | }; |
| | | } |
| | | |
| | | // 向后兼容的默认导出 |
| | | export default function useFormDataSimple(initData) { |
| | | const form = reactive(clone(initData, true)); |
| | | |
| | | function resetForm() { |
| | |
| | | const tableSwitch = ref(false); |
| | | // 处理节点点击 |
| | | const handleNodeClick = (data) => { |
| | | console.log("点击节点", data); |
| | | rowClickData.value = data; // 存储当前点击的节点数据 |
| | | tableSwitch.value = true; |
| | | // 切换节点时重置到第一页 |
| | | queryParams.current = 1; |
| | | queryParams.treeId = data.id; |
| | | getArchiveListData(); |
| | | }; |
| | | const rowClickData = ref({}); // 存储当前点击的节点数据 |
| | | const archiveDialogs = ref(null); // 表格组件引用 |
| | | // 新增归档 |
| | | const add = () => { |
| | |
| | | // 确保组件引用存在后再调用方法 |
| | | nextTick(() => { |
| | | if (archiveDialogs.value && typeof archiveDialogs.value.initForm === 'function') { |
| | | archiveDialogs.value.initForm(); // 重置表单 |
| | | archiveDialogs.value.initForm(rowClickData.value); // 重置表单 |
| | | } |
| | | }); |
| | | } catch (error) { |
| | |
| | | const initTreeDataId = ref(null); |
| | | const fileUploadRef = ref(null); |
| | | const initForm = (val) => { |
| | | initTreeDataId.value = val.value.id || null; // 确保 initTreeDataId 初始化为 null |
| | | initTreeDataId.value = val.id || null; // 确保 initTreeDataId 初始化为 null |
| | | ruleForm.value = {}; |
| | | ruleForm.value.treeId = val.value.id || null; // 确保 treeId 初始化为 null |
| | | ruleForm.value.treeId = val.id || null; // 确保 treeId 初始化为 null |
| | | nextTick(() => { |
| | | fileUploadRef.value.init(); |
| | | }); |
| | |
| | | }); |
| | | return; |
| | | } |
| | | // 发送 emit 事件 |
| | | |
| | | // 关闭对话框 |
| | | centerDialogVisible.value = false; |
| | | } catch (error) { |
| | | ElMessage({ |
| | |
| | | @selection-change="handleSelectionChange" |
| | | :operations="['edit', 'viewRow']" |
| | | :operationsWidth="200" |
| | | :show-overflow-tooltip="false" |
| | | > |
| | | <!-- 字段名称列的自定义插槽 - 显示为标签 --> |
| | | <template |
| | |
| | | import Coal from "./mould/coal.vue"; |
| | | import coalQualityMaintenance from "./mould/coalQualityMaintenance.vue"; |
| | | import coalMeiZhiZiDuanWeiHu from "./mould/coalMeiZhiZiDuanWeiHu.vue"; |
| | | import Descriptions from "@/components/dialog/Descriptions.vue"; |
| | | |
| | | // ===== API 服务导入 ===== |
| | | import { delSupply, getSupply } from "@/api/basicInformation/supplier.js"; |
| | |
| | | import { |
| | | getCoalFieldList, |
| | | getCoalPlanList, |
| | | delCoalPlan, |
| | | } from "@/api/basicInformation/coalQualityMaintenance"; |
| | | |
| | | import { useDelete } from "@/hooks/useDelete.js"; |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | // ===== 响应式状态管理 ===== |
| | | // 弹窗控制状态 |
| | | const showDialog = ref(false); |
| | | const currentViewData = ref({}); // 当前查看的数据 |
| | | |
| | | |
| | | const dialogFormVisible = ref(false); |
| | | const form = ref({}); |
| | | const title = ref(""); |
| | |
| | | const getUserList = async () => { |
| | | try { |
| | | const res = await testUserList(); |
| | | console.log("获取用户列表数据:", res); |
| | | console.log("userMap:", userMap.value); |
| | | if (res && res.data) { |
| | | userList.value = res.data; |
| | | userList.value.forEach((user) => { |
| | | userMap.value[user.userId] = user.username; |
| | | userMap.value[user.userId] = user.nickName; |
| | | }); |
| | | } |
| | | } catch (error) { |
| | |
| | | * 批量删除处理 |
| | | * @description 批量删除选中的记录 |
| | | */ |
| | | const handleDelete = async () => { |
| | | if (selectedRows.value.length === 0) { |
| | | ElMessage.warning("请选择要删除的数据"); |
| | | return; |
| | | } |
| | | |
| | | const deleteIds = selectedRows.value.map((item) => item.id); |
| | | |
| | | try { |
| | | await ElMessageBox.confirm("确定删除选中的数据吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }); |
| | | |
| | | const deleteApiMap = { |
| | | const deleteApiMap = { |
| | | supplier: delSupply, |
| | | coal: delCoalInfo, |
| | | coalQualityMaintenance: () => { |
| | | throw new Error("delCoalQuality API not imported"); |
| | | }, |
| | | coalQualityMaintenance: delCoalPlan, |
| | | customer: delCustomer, |
| | | coalMeiZhiZiDuanWeiHu: deleteCoalField, |
| | | }; |
| | | |
| | | const deleteApi = deleteApiMap[tabName.value]; |
| | | if (!deleteApi) { |
| | | ElMessage.error("删除接口未配置"); |
| | | return; |
| | | } |
| | | console.log(deleteIds); |
| | | const res = await deleteApi(deleteIds); |
| | | |
| | | if (res.code !== 200 && res.msg !== "操作成功") { |
| | | ElMessage.error("删除失败:" + res.msg); |
| | | return; |
| | | } |
| | | |
| | | ElMessage.success("删除成功"); |
| | | await getList(); |
| | | } catch (error) { |
| | | if (error.message !== "cancel") { |
| | | console.error("删除操作失败:", error); |
| | | ElMessage.error("删除失败,请稍后再试"); |
| | | } else { |
| | | ElMessage.info("已取消删除操作"); |
| | | } |
| | | } finally { |
| | | selectedRows.value = []; |
| | | } |
| | | }; |
| | | const {handleDeleteBatch :handleDelete} = useDelete({ |
| | | deleteApi: () => deleteApiMap[tabName.value], |
| | | selectedRows: selectedRows, |
| | | getList: () => getList, |
| | | tableData: tableData, |
| | | total: total, |
| | | confirmText: "确认删除选中的数据吗?", |
| | | successText: "删除成功", |
| | | }) |
| | | |
| | | /** |
| | | * 关闭弹窗处理 |
| | |
| | | </el-form-item> |
| | | <el-form-item label="维护人姓名" prop="maintainerId"> |
| | | <el-input |
| | | :value="userStore.name || ''" |
| | | :value="userStore.nickName || ''" |
| | | placeholder="维护人姓名" |
| | | disabled |
| | | /> |
| | |
| | | required: true, |
| | | type: Object, |
| | | }); |
| | | // 在组件挂载时获取用户信息 |
| | | onMounted(async () => { |
| | | // 如果store中没有用户信息,则获取用户信息 |
| | | if (!userStore.name) { |
| | | try { |
| | | await userStore.getInfo() |
| | | // 自动填充维护人ID |
| | | if (props.addOrEdit === 'add') { |
| | | formData.value.maintainerId = userStore.id |
| | | } |
| | | } catch (error) { |
| | | console.error('获取用户信息失败:', error) |
| | | } |
| | | } else { |
| | | // 自动填充维护人ID |
| | | if (props.addOrEdit === 'add') { |
| | | formData.value.maintainerId = userStore.id |
| | | } |
| | | } |
| | | }) |
| | | |
| | | const emit = defineEmits(['submit', 'handleBeforeClose', 'update:coalDialogFormVisible']) |
| | | // 表单引用 |
| | |
| | | if (!formRef.value) return |
| | | await formRef.value.validate(async (valid, fields) => { |
| | | if (valid) { |
| | | delete formData.value.maintainerName // 删除显示用的字段,只保留ID |
| | | |
| | | // 确保maintainerId有值 |
| | | if (!formData.value.maintainerId) { |
| | |
| | | emit('update:coalDialogFormVisible', false) |
| | | } |
| | | const rules = reactive({ |
| | | supplierName: [ |
| | | {required: true, message: "请输入供货商名称", trigger: "blur"}, |
| | | ], |
| | | identifyNumber: [ |
| | | {required: true, message: "请正确输入纳税人识别号", trigger: "blur"}, |
| | | {min: 17, max: 20, message: "请输入17-20位纳税人识别号", trigger: "blur"}, |
| | | coal: [ |
| | | {required: true, message: "请输入煤种名称", trigger: "blur"}, |
| | | ], |
| | | }); |
| | | |
| | |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="单价(不含税)" prop="priceExcludingTax"> |
| | | <el-form-item label="单价(含税)" prop="priceIncludingTax"> |
| | | <el-input |
| | | v-model.number="form.priceExcludingTax" |
| | | placeholder="请输入" |
| | | v-model.number="form.priceIncludingTax" |
| | | placeholder="请输入含税单价" |
| | | @blur="handlePriceBlur" |
| | | :disabled="isViewMode" |
| | | > |
| | |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="单价(含税)" prop="priceIncludingTax"> |
| | | <el-form-item label="单价(不含税)" prop="priceExcludingTax"> |
| | | <el-input |
| | | v-model.number="form.priceIncludingTax" |
| | | v-model.number="form.priceExcludingTax" |
| | | placeholder="自动计算" |
| | | disabled |
| | | > |
| | |
| | | defineExpose({ |
| | | getDropdownData, |
| | | }); |
| | | // 数值格式化工具函数 |
| | | const toFixed = (num, precision = 2) => { |
| | | if (isNaN(num) || num === null || num === undefined || num === "") { |
| | | return 0; |
| | | } |
| | | return ( |
| | | Math.floor(parseFloat(num) * Math.pow(10, precision)) / |
| | | Math.pow(10, precision) |
| | | ); |
| | | return Number((Math.floor(parseFloat(num) * Math.pow(10, precision)) / Math.pow(10, precision)).toFixed(precision)); |
| | | }; |
| | | // 含税单价计算 |
| | | const unitPriceWithTax = computed(() => { |
| | | const priceExcludingTax = parseFloat(form.value.priceExcludingTax) || 0; |
| | | const taxRate = parseFloat(form.value.taxRate) || 0; |
| | | if (!priceExcludingTax || !taxRate) { |
| | | return 0; |
| | | } |
| | | const result = priceExcludingTax * (1 + taxRate / 100); |
| | | return toFixed(result, 2); |
| | | }); |
| | | |
| | | // 含税总价计算 |
| | | const totalUnitPriceWithTax = computed(() => { |
| | | const priceExcludingTax = parseFloat(form.value.priceExcludingTax) || 0; |
| | | const taxRate = parseFloat(form.value.taxRate) || 0; |
| | | const purchaseQuantity = parseFloat(form.value.purchaseQuantity) || 0; |
| | | // 安全获取数值 |
| | | const safeNumber = (value) => { |
| | | const num = parseFloat(value); |
| | | return isNaN(num) ? 0 : num; |
| | | }; |
| | | |
| | | if (!priceExcludingTax || !taxRate || !purchaseQuantity) { |
| | | return 0; |
| | | } |
| | | // 计算逻辑 - 基于含税单价计算不含税价格 |
| | | const calculatePrices = () => { |
| | | const priceIncludingTax = safeNumber(form.value.priceIncludingTax); // 含税单价 |
| | | const taxRate = safeNumber(form.value.taxRate); // 税率 |
| | | const quantity = safeNumber(form.value.purchaseQuantity); // 采购数量 |
| | | |
| | | const unitPriceWithTaxValue = priceExcludingTax * (1 + taxRate / 100); |
| | | const result = unitPriceWithTaxValue * purchaseQuantity; |
| | | return toFixed(result, 2); |
| | | }); |
| | | // 1. 根据含税单价和税率计算不含税单价 |
| | | // 不含税单价 = 含税单价 / (1 + 税率/100) |
| | | const priceExcludingTax = priceIncludingTax && taxRate |
| | | ? toFixed(priceIncludingTax / (1 + taxRate / 100), 2) |
| | | : 0; |
| | | |
| | | // 不含税总价计算 |
| | | const taxExclusiveTotalPrice = computed(() => { |
| | | const purchaseQuantity = parseFloat(form.value.purchaseQuantity) || 0; |
| | | const priceExcludingTax = parseFloat(form.value.priceExcludingTax) || 0; |
| | | // 2. 计算不含税总价 = 不含税单价 × 数量 |
| | | const totalPriceExcludingTax = priceExcludingTax && quantity |
| | | ? toFixed(priceExcludingTax * quantity, 2) |
| | | : 0; |
| | | |
| | | if (!purchaseQuantity || !priceExcludingTax) { |
| | | return 0; |
| | | } |
| | | // 3. 计算含税总价 = 含税单价 × 数量 |
| | | const totalPriceIncludingTax = priceIncludingTax && quantity |
| | | ? toFixed(priceIncludingTax * quantity, 2) |
| | | : 0; |
| | | |
| | | const result = purchaseQuantity * priceExcludingTax; |
| | | return toFixed(result, 2); |
| | | }); |
| | | // 更新表单数据 |
| | | form.value.priceExcludingTax = priceExcludingTax; |
| | | form.value.totalPriceExcludingTax = totalPriceExcludingTax; |
| | | form.value.totalPriceIncludingTax = totalPriceIncludingTax; |
| | | }; |
| | | |
| | | // 监听计算值变化,同步到 form 对象中 |
| | | watch(unitPriceWithTax, (newValue) => { |
| | | form.value.priceIncludingTax = newValue; |
| | | }); |
| | | |
| | | watch(totalUnitPriceWithTax, (newValue) => { |
| | | form.value.totalPriceIncludingTax = newValue; |
| | | }); |
| | | |
| | | watch(taxExclusiveTotalPrice, (newValue) => { |
| | | form.value.totalPriceExcludingTax = newValue; |
| | | }); |
| | | // 监听表单对象变化,用于处理编辑模式下的数据加载和实时计算 |
| | | watch( |
| | | () => [form.value.priceIncludingTax, form.value.taxRate, form.value.purchaseQuantity], |
| | | () => { |
| | | // 防抖处理,避免频繁计算 |
| | | nextTick(() => { |
| | | calculatePrices(); |
| | | }); |
| | | }, |
| | | { deep: true } |
| | | ); |
| | | |
| | | const userStore = useUserStore(); |
| | | const userInfo = ref({}); |
| | | const match = () => { |
| | | return userInfo.value.nickName || "未知用户"; |
| | | }; |
| | | // 处理税率输入框失焦,确保精度 |
| | | // 处理税率输入框失焦事件 |
| | | const handleTaxRateBlur = () => { |
| | | if ( |
| | | form.value.taxRate !== null && |
| | | form.value.taxRate !== undefined && |
| | | form.value.taxRate !== "" |
| | | ) { |
| | | if (form.value.taxRate !== null && form.value.taxRate !== undefined && form.value.taxRate !== "") { |
| | | form.value.taxRate = toFixed(parseFloat(form.value.taxRate), 2); |
| | | // watch 会自动触发 calculatePrices,不需要手动调用 |
| | | } |
| | | }; |
| | | |
| | | // 处理不含税单价输入框失焦,确保精度 |
| | | // 处理含税单价输入框失焦事件 |
| | | const handlePriceBlur = () => { |
| | | if ( |
| | | form.value.priceExcludingTax !== null && |
| | | form.value.priceExcludingTax !== undefined && |
| | | form.value.priceExcludingTax !== "" |
| | | ) { |
| | | form.value.priceExcludingTax = toFixed( |
| | | parseFloat(form.value.priceExcludingTax), |
| | | 2 |
| | | ); |
| | | if (form.value.priceIncludingTax !== null && form.value.priceIncludingTax !== undefined && form.value.priceIncludingTax !== "") { |
| | | form.value.priceIncludingTax = toFixed(parseFloat(form.value.priceIncludingTax), 2); |
| | | // watch 会自动触发 calculatePrices,不需要手动调用 |
| | | } |
| | | }; |
| | | |
| | | // 处理采购数量输入框失焦,确保精度 |
| | | // 处理采购数量输入框失焦事件 |
| | | const handleQuantityBlur = () => { |
| | | if ( |
| | | form.value.purchaseQuantity !== null && |
| | | form.value.purchaseQuantity !== undefined && |
| | | form.value.purchaseQuantity !== "" |
| | | ) { |
| | | form.value.purchaseQuantity = toFixed( |
| | | parseFloat(form.value.purchaseQuantity), |
| | | 3 |
| | | ); // 数量保留3位小数 |
| | | if (form.value.purchaseQuantity !== null && form.value.purchaseQuantity !== undefined && form.value.purchaseQuantity !== "") { |
| | | form.value.purchaseQuantity = toFixed(parseFloat(form.value.purchaseQuantity), 3); // 数量保留3位小数 |
| | | // watch 会自动触发 calculatePrices,不需要手动调用 |
| | | } |
| | | }; |
| | | |
| | | onMounted(async () => { |
| | | let res = await userStore.getInfo(); |
| | | userInfo.value = res.user; |
| | | getDropdownData() |
| | | |
| | | await getDropdownData(); |
| | | // 组件加载完成后触发一次计算 |
| | | calculatePrices(); |
| | | }); |
| | | const rules = { |
| | | supplierName: [ |
| | |
| | | form.value = { |
| | | supplierName: "", |
| | | coal: "", |
| | | unit: "t", |
| | | unit: "吨", |
| | | purchaseQuantity: "", |
| | | priceExcludingTax: "", |
| | | totalPriceExcludingTax: "", |
| | |
| | | getCoalInfoList, |
| | | deleteProductionInventory, |
| | | } from "@/api/production/index.js"; |
| | | import { getSupplyList } from "@/api/procureMent/index.js" |
| | | import {validateFormData, validateNumber, deepClone, createDefaultProductionRow} from "@/utils/production"; |
| | | import {useCoalData} from "./useCoalData"; |
| | | import useUserStore from "@/store/modules/user"; |
| | |
| | | ]; |
| | | |
| | | const formalDatabaseColumns = ref([ |
| | | {prop: "supplierName", label: "供应商名称", minwidth: 150 |
| | | // ,formatter: (row) => { |
| | | // console.log(row); |
| | | // return supplierList.value[row.supplierId] || "--"; |
| | | // } |
| | | {prop: "supplierId", label: "供应商名称", minwidth: 150 |
| | | ,formatter: (row) => { |
| | | return supplierList.value.find(supplier => supplier.id === row.supplierId)?.supplierName || "--"; |
| | | } |
| | | }, |
| | | {prop: "coalId", label: "煤种", minwidth: 60, |
| | | formatter: (row) => { |
| | | // return coalList.value[row.coalId].coal || "--"; |
| | | return coalList.value.find(coal => coal.id === row.coalId)?.coal || "--"; |
| | | } |
| | | }, |
| | |
| | | // 获取配置数据 |
| | | const handlData = async () => { |
| | | innerVisible.value = true; |
| | | let getSupplier = await getOfficialAll(); |
| | | let OfficialAll = await getOfficialAll(); |
| | | let getSupplierList = await getSupplyList(); |
| | | let getCoalName = await getCoalInfoList(); |
| | | coalList.value = getCoalName.data || []; |
| | | supplierList.value = getSupplier.data || []; |
| | | if (getSupplier.code === 200) { |
| | | formalDatabaseData.value = getSupplier.data; |
| | | supplierList.value = getSupplierList.data || []; |
| | | if (OfficialAll.code === 200) { |
| | | formalDatabaseData.value = OfficialAll.data; |
| | | const existingOfficialIds = tableData.value |
| | | .map((item) => item.officialId) |
| | | .filter((id) => id); |
| | |
| | | <template> |
| | | <div> |
| | | <div class="app-container"> |
| | | <!-- 搜索表单 --> |
| | | <el-form :inline="true" :model="queryParams" class="search-form"> |
| | | <el-form-item label="搜索"> |
| | |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="煤质方案" prop="qualityPlan"> |
| | | <el-select v-model="form.qualityPlan" placeholder="请选择" @change="coalPlanByIdList" clearable> |
| | | <el-form-item label="煤质方案" prop="coalPlanId"> |
| | | <el-select v-model="form.coalPlanId" placeholder="请选择" @change="coalPlanByIdList" clearable> |
| | | <el-option |
| | | v-for="dict in qualityPlanOption" |
| | | :key="dict.id" |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="煤质方案" prop="coalPlanId"> |
| | | <el-select v-model="mergeForm.coalPlanId" placeholder="请选择" @change="coalPlanByIdList" clearable> |
| | | <el-option |
| | | v-for="dict in qualityPlanOption" |
| | | :key="dict.id" |
| | | :label="dict.plan" |
| | | :value="dict.id" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-divider></el-divider> |
| | | <el-row> |
| | | <el-col :span="12" v-for="item in filteredList" :key="item.id"> |
| | |
| | | totalPriceIncludingTax: '', |
| | | priceExcludingTax: '', |
| | | totalPriceExcludingTax: '', |
| | | qualityPlan: '', |
| | | coalPlanId: '', |
| | | pId: '', |
| | | }, |
| | | mergeForm: { |
| | |
| | | totalPriceIncludingTax: '', |
| | | priceExcludingTax: '', |
| | | totalPriceExcludingTax: '', |
| | | qualityPlan: '', |
| | | coalPlanId: '', |
| | | pId: '', |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请输入供应商名称", trigger: "blur" }], |
| | | coal: [{ required: true, message: "请输入煤种", trigger: "blur" }], |
| | | unit: [{ required: true, message: "请输入单位", trigger: "blur" }], |
| | | qualityPlan: [{ required: true, message: "请选择", trigger: "change" }], |
| | | coalPlanId: [{ required: true, message: "请选择", trigger: "change" }], |
| | | }, |
| | | mergeRules: { |
| | | supplierName: [{ required: true, message: "请输入供应商名称", trigger: "blur" }], |
| | | coal: [{ required: true, message: "请输入煤种", trigger: "blur" }], |
| | | unit: [{ required: true, message: "请输入单位", trigger: "blur" }], |
| | | qualityPlan: [{ required: true, message: "请选择", trigger: "change" }], |
| | | coalPlanId: [{ required: true, message: "请选择", trigger: "change" }], |
| | | } |
| | | }) |
| | | |