人员台账增加民族筛选、补贴配置页面、人员薪资修改工资表、增加厂家管理页面、库存管理增加来源字段和废品库
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // æ¥è¯¢è¡¥è´´é
ç½®å表 |
| | | export function listSubsidyConfiguration(query) { |
| | | return request({ |
| | | url: "/subsidyConfiguration/list", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // ä¿å补贴é
ç½® |
| | | export function saveSubsidyConfiguration(data) { |
| | | return request({ |
| | | url: "/subsidyConfiguration/save", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">åå®¶æ¡£æ¡ï¼</span> |
| | | <el-input v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥åå®¶åç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" /> |
| | | <el-button type="primary" |
| | | @click="handleQuery" |
| | | style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination"></PIMTable> |
| | | </div> |
| | | <el-dialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢åå®¶ä¿¡æ¯' : 'ç¼è¾åå®¶ä¿¡æ¯'" |
| | | width="70%" |
| | | @close="closeDia"> |
| | | <el-form :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åå®¶åç§°ï¼" |
| | | prop="supplierName"> |
| | | <el-input v-model="form.supplierName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="纳ç¨äººè¯å«å·ï¼" |
| | | prop="taxpayerIdentificationNum"> |
| | | <el-input v-model="form.taxpayerIdentificationNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸å°åï¼" |
| | | prop="companyAddress"> |
| | | <el-input v-model="form.companyAddress" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸çµè¯ï¼" |
| | | prop="companyPhone"> |
| | | <el-input v-model="form.companyPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="弿·è¡ï¼" |
| | | prop="bankAccountName"> |
| | | <el-input v-model="form.bankAccountName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è´¦å·ï¼" |
| | | prop="bankAccountNum"> |
| | | <el-input v-model="form.bankAccountNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è系人ï¼" |
| | | prop="contactUserName"> |
| | | <el-input v-model="form.contactUserName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="èç³»çµè¯ï¼" |
| | | prop="contactUserPhone"> |
| | | <el-input v-model="form.contactUserPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤äººï¼" |
| | | prop="maintainUserId"> |
| | | <el-select v-model="form.maintainUserId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | disabled> |
| | | <el-option v-for="item in userList" |
| | | :key="item.nickName" |
| | | :label="item.nickName" |
| | | :value="item.userId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤æ¶é´ï¼" |
| | | prop="maintainTime"> |
| | | <el-date-picker style="width: 100%" |
| | | v-model="form.maintainTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åå®¶ç±»åï¼" |
| | | prop="supplierType"> |
| | | <el-select v-model="form.supplierType" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option label="ç²" |
| | | value="ç²" /> |
| | | <el-option label="ä¹" |
| | | value="ä¹" /> |
| | | <el-option label="ä¸" |
| | | value="ä¸" /> |
| | | <el-option label="ä¸" |
| | | value="ä¸" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦ç½ååï¼" |
| | | prop="isWhite"> |
| | | <el-select v-model="form.isWhite" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option label="æ¯" |
| | | :value="0" /> |
| | | <el-option label="å¦" |
| | | :value="1" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- å家导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog :title="upload.title" |
| | | v-model="upload.open" |
| | | width="400px" |
| | | append-to-body> |
| | | <el-upload ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url + '?updateSupport=' + upload.updateSupport" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :on-error="handleFileError" |
| | | :auto-upload="false" |
| | | drag> |
| | | <el-icon class="el-icon--upload"><upload-filled /></el-icon> |
| | | <div class="el-upload__text">å°æä»¶æå°æ¤å¤ï¼æ<em>ç¹å»ä¸ä¼ </em></div> |
| | | <template #tip> |
| | | <div class="el-upload__tip text-center"> |
| | | <span>ä»
å
许导å
¥xlsãxlsxæ ¼å¼æä»¶ã</span> |
| | | <el-link type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline" |
| | | @click="importTemplate">ä¸è½½æ¨¡æ¿</el-link> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="upload.open = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <FileList v-if="fileListDialogVisible" |
| | | v-model:visible="fileListDialogVisible" |
| | | record-type="supplier_manage" |
| | | :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { delSupplier } from "@/api/basicData/supplierManageFile.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addSupplier, |
| | | getSupplier, |
| | | listSupplier, |
| | | updateSupplier, |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "åå®¶åç§°", |
| | | prop: "supplierName", |
| | | width: 250, |
| | | }, |
| | | { |
| | | label: "åå®¶ç±»å", |
| | | prop: "supplierType", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "纳ç¨äººè¯å«å·", |
| | | prop: "taxpayerIdentificationNum", |
| | | width: 230, |
| | | }, |
| | | { |
| | | label: "å
¬å¸å°å", |
| | | prop: "companyAddress", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "èç³»æ¹å¼", |
| | | prop: "companyPhone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "弿·è¡", |
| | | prop: "bankAccountName", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è´¦å·", |
| | | prop: "bankAccountNum", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è系人", |
| | | prop: "contactUserName", |
| | | }, |
| | | { |
| | | label: "èç³»çµè¯", |
| | | prop: "contactUserPhone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "ç»´æ¤äºº", |
| | | prop: "maintainUserName", |
| | | }, |
| | | |
| | | { |
| | | label: "ç»´æ¤æ¶é´", |
| | | prop: "maintainTime", |
| | | width: 100, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openForm("edit", row); |
| | | }, |
| | | }, |
| | | { |
| | | //èµè´¨éä»¶ |
| | | name: "èµè´¨æä»¶", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openFileDialog(row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const fileListDialogVisible = ref(false); |
| | | const recordId = ref(); |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | }, |
| | | form: { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | companyAddress: "", |
| | | companyPhone: "", |
| | | bankAccountName: "", |
| | | bankAccountNum: "", |
| | | contactUserName: "", |
| | | contactUserPhone: "", |
| | | maintainUserId: "", |
| | | maintainTime: "", |
| | | supplierType: "", |
| | | isWhite: "", |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxpayerIdentificationNum: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | companyAddress: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | companyPhone: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountNum: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserName: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserPhone: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | maintainUserId: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | maintainTime: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | supplierType: [ |
| | | { required: true, message: "è¯·éæ©åå®¶ç±»å", trigger: "change" }, |
| | | ], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | /** æäº¤ä¸ä¼ æä»¶ */ |
| | | function submitFileForm() { |
| | | upload.isUploading = true; |
| | | proxy.$refs["uploadRef"].submit(); |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listSupplier({ ...searchForm.value, ...page, isWhite: 1 }).then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼å家导å
¥ï¼ |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ï¼å家导å
¥ï¼ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // æ¯å¦æ´æ°å·²ç»åå¨çç¨æ·æ°æ® |
| | | updateSupport: 1, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import", |
| | | }); |
| | | /** 导å
¥æé®æä½ */ |
| | | function handleImport() { |
| | | upload.title = "å家导å
¥"; |
| | | upload.open = true; |
| | | } |
| | | /** ä¸è½½æ¨¡æ¿ */ |
| | | function importTemplate() { |
| | | proxy.download("/system/supplier/downloadTemplate", {}, "å家导å
¥æ¨¡æ¿.xlsx"); |
| | | } |
| | | |
| | | /**æä»¶ä¸ä¼ ä¸å¤ç */ |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ æåå¤ç */ |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.isUploading = false; |
| | | if (response.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | upload.open = false; |
| | | proxy.$refs["uploadRef"].clearFiles(); |
| | | getList(); |
| | | } else if (response.code === 500) { |
| | | proxy.$modal.msgError(response.msg); |
| | | } else { |
| | | proxy.$modal.msgWarning(response.msg); |
| | | } |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ 失败å¤ç */ |
| | | const handleFileError = (error, file, fileList) => { |
| | | upload.isUploading = false; |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | form.value.maintainUserId = userStore.id; |
| | | form.value.maintainTime = getCurrentDate(); |
| | | userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | getSupplier(row.id).then(res => { |
| | | form.value = { ...res.data }; |
| | | }); |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | submitEdit(); |
| | | } else { |
| | | submitAdd(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | // æäº¤æ°å¢ |
| | | const submitAdd = () => { |
| | | addSupplier(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // æäº¤ä¿®æ¹ |
| | | const submitEdit = () => { |
| | | updateSupplier(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download( |
| | | "/system/supplier/export", |
| | | { isWhite: 1 }, |
| | | "åå®¶æ¡£æ¡.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter( |
| | | item => item.maintainUserName !== userStore.nickName |
| | | ); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | return; |
| | | } |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | delSupplier(ids) |
| | | .then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | |
| | | defineExpose({ |
| | | getList, |
| | | }); |
| | | </script> |
| | | |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <div class="search_form"> |
| | | <div style="margin-bottom: 10px;"> |
| | | <span class="search_title">åå®¶æ¡£æ¡ï¼</span> |
| | | <el-input v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥åå®¶åç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" /> |
| | | <el-button type="primary" |
| | | @click="handleQuery" |
| | | style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div style="margin-bottom: 10px;"> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢åå®¶</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="info" |
| | | plain |
| | | icon="Upload" |
| | | @click="handleImport">导å
¥</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination"></PIMTable> |
| | | </div> |
| | | <el-dialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢åå®¶ä¿¡æ¯' : 'ç¼è¾åå®¶ä¿¡æ¯'" |
| | | width="70%" |
| | | @close="closeDia"> |
| | | <el-form :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åå®¶åç§°ï¼" |
| | | prop="supplierName"> |
| | | <el-input v-model="form.supplierName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="纳ç¨äººè¯å«å·ï¼" |
| | | prop="taxpayerIdentificationNum"> |
| | | <el-input v-model="form.taxpayerIdentificationNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸å°åï¼" |
| | | prop="companyAddress"> |
| | | <el-input v-model="form.companyAddress" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸çµè¯ï¼" |
| | | prop="companyPhone"> |
| | | <el-input v-model="form.companyPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="弿·è¡ï¼" |
| | | prop="bankAccountName"> |
| | | <el-input v-model="form.bankAccountName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è´¦å·ï¼" |
| | | prop="bankAccountNum"> |
| | | <el-input v-model="form.bankAccountNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è系人ï¼" |
| | | prop="contactUserName"> |
| | | <el-input v-model="form.contactUserName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="èç³»çµè¯ï¼" |
| | | prop="contactUserPhone"> |
| | | <el-input v-model="form.contactUserPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤äººï¼" |
| | | prop="maintainUserId"> |
| | | <el-select v-model="form.maintainUserId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | disabled> |
| | | <el-option v-for="item in userList" |
| | | :key="item.nickName" |
| | | :label="item.nickName" |
| | | :value="item.userId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤æ¶é´ï¼" |
| | | prop="maintainTime"> |
| | | <el-date-picker style="width: 100%" |
| | | v-model="form.maintainTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åå®¶ç±»åï¼" |
| | | prop="supplierType"> |
| | | <el-select v-model="form.supplierType" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option label="ç²" |
| | | value="ç²" /> |
| | | <el-option label="ä¹" |
| | | value="ä¹" /> |
| | | <el-option label="ä¸" |
| | | value="ä¸" /> |
| | | <el-option label="ä¸" |
| | | value="ä¸" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦ç½ååï¼" |
| | | prop="isWhite"> |
| | | <el-select v-model="form.isWhite" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option label="æ¯" |
| | | :value="0" /> |
| | | <el-option label="å¦" |
| | | :value="1" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- å家导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog :title="upload.title" |
| | | v-model="upload.open" |
| | | width="400px" |
| | | append-to-body> |
| | | <el-upload ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url + '?updateSupport=' + upload.updateSupport" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :on-error="handleFileError" |
| | | :auto-upload="false" |
| | | drag> |
| | | <el-icon class="el-icon--upload"><upload-filled /></el-icon> |
| | | <div class="el-upload__text">å°æä»¶æå°æ¤å¤ï¼æ<em>ç¹å»ä¸ä¼ </em></div> |
| | | <template #tip> |
| | | <div class="el-upload__tip text-center"> |
| | | <span>ä»
å
许导å
¥xlsãxlsxæ ¼å¼æä»¶ã</span> |
| | | <el-link type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline" |
| | | @click="importTemplate">ä¸è½½æ¨¡æ¿</el-link> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="upload.open = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <FileList v-if="fileListDialogVisible" |
| | | v-model:visible="fileListDialogVisible" |
| | | record-type="supplier_manage" |
| | | :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { delSupplier } from "@/api/basicData/supplierManageFile.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addSupplier, |
| | | getSupplier, |
| | | listSupplier, |
| | | updateSupplier, |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "åå®¶åç§°", |
| | | prop: "supplierName", |
| | | width: 250, |
| | | }, |
| | | { |
| | | label: "åå®¶ç±»å", |
| | | prop: "supplierType", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "纳ç¨äººè¯å«å·", |
| | | prop: "taxpayerIdentificationNum", |
| | | width: 230, |
| | | }, |
| | | { |
| | | label: "å
¬å¸å°å", |
| | | prop: "companyAddress", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "èç³»æ¹å¼", |
| | | prop: "companyPhone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "弿·è¡", |
| | | prop: "bankAccountName", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è´¦å·", |
| | | prop: "bankAccountNum", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è系人", |
| | | prop: "contactUserName", |
| | | }, |
| | | { |
| | | label: "èç³»çµè¯", |
| | | prop: "contactUserPhone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "ç»´æ¤äºº", |
| | | prop: "maintainUserName", |
| | | }, |
| | | |
| | | { |
| | | label: "ç»´æ¤æ¶é´", |
| | | prop: "maintainTime", |
| | | width: 100, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openForm("edit", row); |
| | | }, |
| | | }, |
| | | { |
| | | //èµè´¨éä»¶ |
| | | name: "èµè´¨æä»¶", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openFileDialog(row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const fileListDialogVisible = ref(false); |
| | | const recordId = ref(); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | }, |
| | | form: { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | companyAddress: "", |
| | | companyPhone: "", |
| | | bankAccountName: "", |
| | | bankAccountNum: "", |
| | | contactUserName: "", |
| | | contactUserPhone: "", |
| | | maintainUserId: "", |
| | | maintainTime: "", |
| | | supplierType: "", |
| | | isWhite: "", |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxpayerIdentificationNum: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | companyAddress: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | companyPhone: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountNum: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserName: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserPhone: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | maintainUserId: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | maintainTime: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | supplierType: [ |
| | | { required: true, message: "è¯·éæ©åå®¶ç±»å", trigger: "change" }, |
| | | ], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | /** æäº¤ä¸ä¼ æä»¶ */ |
| | | function submitFileForm() { |
| | | upload.isUploading = true; |
| | | proxy.$refs["uploadRef"].submit(); |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listSupplier({ ...searchForm.value, ...page, isWhite: 0 }).then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼å家导å
¥ï¼ |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ï¼å家导å
¥ï¼ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // æ¯å¦æ´æ°å·²ç»åå¨çç¨æ·æ°æ® |
| | | updateSupport: 1, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import", |
| | | }); |
| | | /** 导å
¥æé®æä½ */ |
| | | function handleImport() { |
| | | upload.title = "å家导å
¥"; |
| | | upload.open = true; |
| | | } |
| | | /** ä¸è½½æ¨¡æ¿ */ |
| | | function importTemplate() { |
| | | proxy.download("/system/supplier/downloadTemplate", {}, "å家导å
¥æ¨¡æ¿.xlsx"); |
| | | } |
| | | |
| | | /**æä»¶ä¸ä¼ ä¸å¤ç */ |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ æåå¤ç */ |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.isUploading = false; |
| | | if (response.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | upload.open = false; |
| | | proxy.$refs["uploadRef"].clearFiles(); |
| | | getList(); |
| | | } else if (response.code === 500) { |
| | | proxy.$modal.msgError(response.msg); |
| | | } else { |
| | | proxy.$modal.msgWarning(response.msg); |
| | | } |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ 失败å¤ç */ |
| | | const handleFileError = (error, file, fileList) => { |
| | | upload.isUploading = false; |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | form.value.maintainUserId = userStore.id; |
| | | form.value.maintainTime = getCurrentDate(); |
| | | userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | getSupplier(row.id).then(res => { |
| | | form.value = { ...res.data }; |
| | | }); |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | submitEdit(); |
| | | } else { |
| | | submitAdd(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | // æäº¤æ°å¢ |
| | | const submitAdd = () => { |
| | | addSupplier(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // æäº¤ä¿®æ¹ |
| | | const submitEdit = () => { |
| | | updateSupplier(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download( |
| | | "/system/supplier/export", |
| | | { isWhite: 0 }, |
| | | "åå®¶æ¡£æ¡.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter( |
| | | item => item.maintainUserName !== userStore.nickName |
| | | ); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | return; |
| | | } |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | delSupplier(ids) |
| | | .then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | |
| | | defineExpose({ |
| | | getList, |
| | | }); |
| | | </script> |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog v-model="dialogFormVisible" |
| | | title="ä¸ä¼ éä»¶" |
| | | width="50%" |
| | | @close="closeDia"> |
| | | <div style="margin-bottom: 10px;text-align: right"> |
| | | <el-upload v-model:file-list="fileList" |
| | | class="upload-demo" |
| | | :action="uploadUrl" |
| | | :on-success="handleUploadSuccess" |
| | | :on-error="handleUploadError" |
| | | name="file" |
| | | :show-file-list="false" |
| | | :headers="headers" |
| | | style="display: inline;margin-right: 10px"> |
| | | <el-button type="primary">ä¸ä¼ éä»¶</el-button> |
| | | </el-upload> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :tableLoading="tableLoading" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | height="500" |
| | | @pagination-change="paginationSearch" |
| | | :total="total" |
| | | :page="page.current" |
| | | :limit="page.size"> |
| | | </PIMTable> |
| | | <pagination style="margin: 10px 0" |
| | | v-show="total > 0" |
| | | @pagination="paginationSearch" |
| | | :total="total" |
| | | :page="page.current" |
| | | :limit="page.size" /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <filePreview ref="filePreviewRef" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | import filePreview from "@/components/filePreview/index.vue"; |
| | | import { |
| | | fileAdd, |
| | | fileDel, |
| | | fileListPage, |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import Pagination from "@/components/PIMTable/Pagination.vue"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const emit = defineEmits(["close"]); |
| | | |
| | | const dialogFormVisible = ref(false); |
| | | const currentId = ref(""); |
| | | const selectedRows = ref([]); |
| | | const filePreviewRef = ref(); |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "æä»¶åç§°", |
| | | prop: "name", |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | operation: [ |
| | | { |
| | | name: "ä¸è½½", |
| | | type: "text", |
| | | clickFun: row => { |
| | | downLoadFile(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "é¢è§", |
| | | type: "text", |
| | | clickFun: row => { |
| | | lookFile(row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | const tableData = ref([]); |
| | | const fileList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const headers = ref({ |
| | | Authorization: "Bearer " + getToken(), |
| | | }); |
| | | const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // ä¸ä¼ çå¾çæå¡å¨å°å |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = row => { |
| | | dialogFormVisible.value = true; |
| | | currentId.value = row.id; |
| | | getList(); |
| | | }; |
| | | const paginationSearch = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | fileListPage({ supplierId: currentId.value, ...page }).then(res => { |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total; |
| | | }); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | dialogFormVisible.value = false; |
| | | emit("close"); |
| | | }; |
| | | // ä¸ä¼ æåå¤ç |
| | | function handleUploadSuccess(res, file) { |
| | | // 妿ä¸ä¼ æå |
| | | if (res.code == 200) { |
| | | const fileRow = {}; |
| | | fileRow.name = res.data.originalName; |
| | | fileRow.url = res.data.tempPath; |
| | | uploadFile(fileRow); |
| | | } else { |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | } |
| | | } |
| | | function uploadFile(file) { |
| | | file.supplierId = currentId.value; |
| | | fileAdd(file).then(res => { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | getList(); |
| | | }); |
| | | } |
| | | // ä¸ä¼ 失败å¤ç |
| | | function handleUploadError() { |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | } |
| | | // ä¸è½½éä»¶ |
| | | const downLoadFile = row => { |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | fileDel(ids).then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // é¢è§éä»¶ |
| | | const lookFile = row => { |
| | | filePreviewRef.value.open(row.url); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <!-- å¨ä½ ç主页é¢ä¸ --> |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-tabs v-model="activeTab" |
| | | @tab-change="handleTabChange"> |
| | | <el-tab-pane label="æ£å¸¸åå®¶" |
| | | name="home"> |
| | | <HomeTab ref="homeTab" /> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="é»åå" |
| | | name="blacklist"> |
| | | <BlacklistTab ref="blacklistTab" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import HomeTab from "./components/HomeTab.vue"; |
| | | import BlacklistTab from "./components/BlacklistTab.vue"; |
| | | |
| | | export default { |
| | | name: "MainPage", |
| | | components: { |
| | | HomeTab, |
| | | BlacklistTab, |
| | | }, |
| | | data() { |
| | | return { |
| | | activeTab: "home", |
| | | }; |
| | | }, |
| | | methods: { |
| | | handleTabChange(tabName) { |
| | | this.activeTab = tabName; |
| | | this.$nextTick(() => { |
| | | if (tabName === "home") { |
| | | this.$refs.homeTab && |
| | | this.$refs.homeTab.getList && |
| | | this.$refs.homeTab.getList(); |
| | | } else if (tabName === "blacklist") { |
| | | this.$refs.blacklistTab && |
| | | this.$refs.blacklistTab.getList && |
| | | this.$refs.blacklistTab.getList(); |
| | | } |
| | | }); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | |
| | | <el-input v-model="formState.unit" |
| | | disabled /> |
| | | </el-form-item> |
| | | <el-form-item label="åå®¶" |
| | | prop="manufacturer"> |
| | | <el-input v-model="formState.manufacturer" |
| | | placeholder="请è¾å
¥åå®¶" /> |
| | | </el-form-item> |
| | | <el-form-item label="åºåç±»å" |
| | | prop="type" |
| | | :rules="[ |
| | |
| | | } |
| | | ]"> |
| | | <el-select v-model="formState.type" |
| | | placeholder="è¯·éæ©åºåç±»å"> |
| | | <el-option label="åæ ¼åºå" |
| | | placeholder="è¯·éæ©åºåç±»å" |
| | | @change="handleTypeChange"> |
| | | <el-option label="åæ ¼åº" |
| | | value="qualified" /> |
| | | <el-option label="ä¸åæ ¼åºå" |
| | | <el-option label="åºååº" |
| | | value="waste" /> |
| | | <el-option label="ä¸åæ ¼åº" |
| | | value="unqualified" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item v-if="formState.type && formState.type !== 'unqualified'" |
| | | label="æ¥æº" |
| | | prop="source" |
| | | :rules="[ |
| | | { |
| | | required: true, |
| | | message: 'è¯·éæ©æ¥æº', |
| | | trigger: 'change', |
| | | } |
| | | ]"> |
| | | <el-select v-model="formState.source" |
| | | placeholder="è¯·éæ©æ¥æº"> |
| | | <el-option v-for="item in sourceOptions" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="åºåæ°é" |
| | |
| | | productModelName: "", |
| | | unit: "", |
| | | type: undefined, |
| | | manufacturer: "", |
| | | source: "", |
| | | qualitity: 0, |
| | | batchNo: null, |
| | | warnNum: 0, |
| | | remark: "", |
| | | }); |
| | | |
| | | const sourceOptions = computed(() => { |
| | | if (formState.value.type === "qualified") { |
| | | return ["éè´å
¥åº", "ç产å
¥åº", "å¤åå
¥åº", "ä¿®å¤å
¥åº"]; |
| | | } else if (formState.value.type === "waste") { |
| | | return ["ç产产ç", "è¿è¾äº§ç", "è£åªäº§ç"]; |
| | | } |
| | | return []; |
| | | }); |
| | | |
| | | const handleTypeChange = val => { |
| | | if (val === "unqualified") { |
| | | formState.value.source = "èªå®ä¹"; |
| | | } else { |
| | | formState.value.source = ""; |
| | | } |
| | | }; |
| | | |
| | | const isShow = computed({ |
| | | get() { |
| | |
| | | productModelName: "", |
| | | unit: "", |
| | | type: undefined, |
| | | manufacturer: "", |
| | | source: "", |
| | | qualitity: 0, |
| | | batchNo: null, |
| | | warnNum: 0, |
| | |
| | | <template> |
| | | <el-card class="form-card" shadow="never"> |
| | | <el-card class="form-card" |
| | | shadow="never"> |
| | | <template #header> |
| | | <span class="card-title"> |
| | | <span class="card-title-line">|</span> |
| | | åºæ¬ä¿¡æ¯ |
| | | </span> |
| | | </template> |
| | | |
| | | <el-row :gutter="24"> |
| | | <el-col :span="5"> |
| | | <el-form-item label="åå·¥ç¼å·" prop="staffNo"> |
| | | <el-input |
| | | v-model="form.staffNo" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="20" |
| | | show-word-limit |
| | | :disabled="operationType !== 'add'" |
| | | /> |
| | | <el-form-item label="åå·¥ç¼å·" |
| | | prop="staffNo"> |
| | | <el-input v-model="form.staffNo" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="20" |
| | | show-word-limit |
| | | :disabled="operationType !== 'add'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="5"> |
| | | <el-form-item label="å§å" prop="staffName"> |
| | | <el-input |
| | | v-model="form.staffName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="50" |
| | | show-word-limit |
| | | /> |
| | | <el-form-item label="å§å" |
| | | prop="staffName"> |
| | | <el-input v-model="form.staffName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="50" |
| | | show-word-limit /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="5"> |
| | | <el-form-item label="å«å" prop="alias"> |
| | | <el-input |
| | | v-model="form.alias" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="50" |
| | | show-word-limit |
| | | /> |
| | | <el-form-item label="å«å" |
| | | prop="alias"> |
| | | <el-input v-model="form.alias" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="50" |
| | | show-word-limit /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="5"> |
| | | <el-form-item label="ææº" prop="phone"> |
| | | <el-input |
| | | v-model="form.phone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="11" |
| | | show-word-limit |
| | | /> |
| | | <el-form-item label="ææº" |
| | | prop="phone"> |
| | | <el-input v-model="form.phone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="11" |
| | | show-word-limit /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="æ§å«" prop="sex"> |
| | | <el-select |
| | | v-model="form.sex" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option label="ç·" value="ç·" /> |
| | | <el-option label="女" value="女" /> |
| | | <el-form-item label="æ§å«" |
| | | prop="sex"> |
| | | <el-select v-model="form.sex" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%"> |
| | | <el-option label="ç·" |
| | | value="ç·" /> |
| | | <el-option label="女" |
| | | value="女" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="24"> |
| | | <el-col :span="5"> |
| | | <el-form-item label="åºçæ¥æ" prop="birthDate"> |
| | | <el-date-picker |
| | | v-model="form.birthDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%" |
| | | clearable |
| | | /> |
| | | <el-form-item label="åºçæ¥æ" |
| | | prop="birthDate"> |
| | | <el-date-picker v-model="form.birthDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="5"> |
| | | <el-form-item label="å¹´é¾" prop="age"> |
| | | <el-input-number |
| | | v-model="form.age" |
| | | :min="0" |
| | | :max="150" |
| | | :precision="0" |
| | | :step="1" |
| | | style="width: 100%" |
| | | /> |
| | | <el-form-item label="å¹´é¾" |
| | | prop="age"> |
| | | <el-input-number v-model="form.age" |
| | | :min="0" |
| | | :max="150" |
| | | :precision="0" |
| | | :step="1" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="5"> |
| | | <el-form-item label="ç±è´¯" prop="nativePlace"> |
| | | <el-input |
| | | v-model="form.nativePlace" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="50" |
| | | show-word-limit |
| | | /> |
| | | <el-form-item label="ç±è´¯" |
| | | prop="nativePlace"> |
| | | <el-input v-model="form.nativePlace" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="50" |
| | | show-word-limit /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="5"> |
| | | <el-form-item label="æ°æ" prop="nation"> |
| | | <el-input |
| | | v-model="form.nation" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="20" |
| | | show-word-limit |
| | | /> |
| | | <el-form-item label="æ°æ" |
| | | prop="nation"> |
| | | <el-select v-model="form.nation" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%"> |
| | | <el-option v-for="dict in nation_type" |
| | | :key="dict.label" |
| | | :label="dict.label" |
| | | :value="dict.label" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="å©å§»ç¶åµ" prop="maritalStatus"> |
| | | <el-select |
| | | v-model="form.maritalStatus" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option label="æªå©" value="æªå©" /> |
| | | <el-option label="å·²å©" value="å·²å©" /> |
| | | <el-option label="离å¼" value="离å¼" /> |
| | | <el-option label="丧å¶" value="丧å¶" /> |
| | | <el-form-item label="å©å§»ç¶åµ" |
| | | prop="maritalStatus"> |
| | | <el-select v-model="form.maritalStatus" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%"> |
| | | <el-option label="æªå©" |
| | | value="æªå©" /> |
| | | <el-option label="å·²å©" |
| | | value="å·²å©" /> |
| | | <el-option label="离å¼" |
| | | value="离å¼" /> |
| | | <el-option label="丧å¶" |
| | | value="丧å¶" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="24"> |
| | | <el-col :span="10"> |
| | | <el-form-item label="è§è²" prop="roleId"> |
| | | <el-select |
| | | v-model="form.roleId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in roleOptions" |
| | | :key="item.roleId" |
| | | :label="item.roleName" |
| | | :value="item.roleId" |
| | | :disabled="item.status == 1" |
| | | /> |
| | | <el-form-item label="è§è²" |
| | | prop="roleId"> |
| | | <el-select v-model="form.roleId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%"> |
| | | <el-option v-for="item in roleOptions" |
| | | :key="item.roleId" |
| | | :label="item.roleName" |
| | | :value="item.roleId" |
| | | :disabled="item.status == 1" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { toRefs } from "vue"; |
| | | import { toRefs, getCurrentInstance } from "vue"; |
| | | |
| | | const props = defineProps({ |
| | | form: { type: Object, required: true }, |
| | | operationType: { type: String, default: "add" }, |
| | | roleOptions: { type: Array, default: () => [] }, |
| | | }); |
| | | const props = defineProps({ |
| | | form: { type: Object, required: true }, |
| | | operationType: { type: String, default: "add" }, |
| | | roleOptions: { type: Array, default: () => [] }, |
| | | }); |
| | | |
| | | const { form, operationType, roleOptions } = toRefs(props); |
| | | const { proxy } = getCurrentInstance(); |
| | | const { nation_type } = proxy.useDict("nation_type"); |
| | | const { form, operationType, roleOptions } = toRefs(props); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .form-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | .form-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .card-title-line { |
| | | color: #f56c6c; |
| | | margin-right: 4px; |
| | | } |
| | | .card-title-line { |
| | | color: #f56c6c; |
| | | margin-right: 4px; |
| | | } |
| | | </style> |
| | | |
| | |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å§åï¼</span> |
| | | <el-input |
| | | v-model="searchForm.staffName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥å§åæç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | | <el-input v-model="searchForm.staffName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥å§åæç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" /> |
| | | <span class="search_title search_title2">é¨é¨ï¼</span> |
| | | <el-tree-select |
| | | v-model="searchForm.sysDeptId" |
| | | :data="deptOptions" |
| | | check-strictly |
| | | :render-after-expand="false" |
| | | style="width: 240px" |
| | | placeholder="è¯·éæ©" |
| | | /> |
| | | <span class="search_title search_title2">å
¥èæ¥æï¼</span> |
| | | <el-date-picker |
| | | v-model="searchForm.contractStartTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | placeholder="è¯·éæ©" |
| | | /> |
| | | <el-tree-select v-model="searchForm.sysDeptId" |
| | | :data="deptOptions" |
| | | check-strictly |
| | | :render-after-expand="false" |
| | | style="width: 240px" |
| | | placeholder="è¯·éæ©" /> |
| | | <span class="search_title search_title2">å
¥èæ¥æï¼</span> |
| | | <el-date-picker v-model="searchForm.contractStartTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | placeholder="è¯·éæ©" /> |
| | | <span class="search_title search_title2">æ°æï¼</span> |
| | | <el-select v-model="searchForm.nation" |
| | | placeholder="è¯·éæ©æ°æ" |
| | | clearable |
| | | style="width: 240px" |
| | | @change="handleQuery"> |
| | | <el-option v-for="dict in nation_type" |
| | | :key="dict.label" |
| | | :label="dict.label" |
| | | :value="dict.label" /> |
| | | </el-select> |
| | | <!-- <span style="margin-left: 10px" class="search_title">ååç»ææ¥æï¼</span> --> |
| | | <!-- <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" |
| | | placeholder="è¯·éæ©" clearable @change="changeDaterange" /> --> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >æç´¢</el-button |
| | | > |
| | | <el-button type="primary" |
| | | @click="handleQuery" |
| | | style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="openFormNewOrEditFormDia('add')">æ°å¢å
¥è</el-button> |
| | | <el-button type="info" @click="handleImport">导å
¥</el-button> |
| | | <el-button type="primary" |
| | | @click="openFormNewOrEditFormDia('add')">æ°å¢å
¥è</el-button> |
| | | <el-button type="info" |
| | | @click="handleImport">导å
¥</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <!-- <el-button type="danger" plain @click="handleDelete">å é¤</el-button> --> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :total="page.total" |
| | | > |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :total="page.total"> |
| | | <template #positiveDate="{ row }"> |
| | | <span :class="getPositiveDateClass(row.positiveDate)">{{ row.positiveDate }}</span> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <show-form-dia ref="formDia" @close="handleQuery"></show-form-dia> |
| | | <new-or-edit-form-dia ref="formDiaNewOrEditFormDia" @close="handleQuery"></new-or-edit-form-dia> |
| | | |
| | | <show-form-dia ref="formDia" |
| | | @close="handleQuery"></show-form-dia> |
| | | <new-or-edit-form-dia ref="formDiaNewOrEditFormDia" |
| | | @close="handleQuery"></new-or-edit-form-dia> |
| | | <!-- 导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body> |
| | | <el-upload |
| | | ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :auto-upload="false" |
| | | drag |
| | | > |
| | | <el-dialog :title="upload.title" |
| | | v-model="upload.open" |
| | | width="400px" |
| | | append-to-body> |
| | | <el-upload ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :auto-upload="false" |
| | | drag> |
| | | <el-icon class="el-icon--upload"><upload-filled /></el-icon> |
| | | <div class="el-upload__text">å°æä»¶æå°æ¤å¤ï¼æ<em>ç¹å»ä¸ä¼ </em></div> |
| | | <template #tip> |
| | | <div class="el-upload__tip text-center"> |
| | | <span>ä»
å
许导å
¥xlsãxlsxæ ¼å¼æä»¶ã</span> |
| | | <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline; margin-left: 5px;" @click="importTemplate">ä¸è½½æ¨¡æ¿</el-link> |
| | | <el-link type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline; margin-left: 5px;" |
| | | @click="importTemplate">ä¸è½½æ¨¡æ¿</el-link> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button type="primary" |
| | | @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="upload.open = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { Search, UploadFilled } from "@element-plus/icons-vue"; |
| | | import {onMounted, ref} from "vue"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import { deptTreeSelect } from "@/api/system/user.js"; |
| | | import {batchDeleteStaffOnJobs, staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import dayjs from "dayjs"; |
| | | import { Search, UploadFilled } from "@element-plus/icons-vue"; |
| | | import { onMounted, ref } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { deptTreeSelect } from "@/api/system/user.js"; |
| | | import { |
| | | batchDeleteStaffOnJobs, |
| | | staffOnJobListPage, |
| | | } from "@/api/personnelManagement/staffOnJob.js"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const NewOrEditFormDia = defineAsyncComponent(() => import("@/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue")); |
| | | const ShowFormDia = defineAsyncComponent(() => import( "@/views/personnelManagement/employeeRecord/components/Show.vue")); |
| | | const NewOrEditFormDia = defineAsyncComponent(() => |
| | | import( |
| | | "@/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue" |
| | | ) |
| | | ); |
| | | const ShowFormDia = defineAsyncComponent(() => |
| | | import("@/views/personnelManagement/employeeRecord/components/Show.vue") |
| | | ); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | staffName: "", |
| | | entryDate: undefined, // å½å
¥æ¥æ |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined, |
| | | }, |
| | | deptOptions: [], |
| | | }); |
| | | const { searchForm, deptOptions } = toRefs(data); |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ç¶æ", |
| | | prop: "staffState", |
| | | dataType: "tag", |
| | | formatData: (params) => { |
| | | if (params == 0) { |
| | | return "离è"; |
| | | } else if (params == 1) { |
| | | return "å¨è"; |
| | | } else { |
| | | return null; |
| | | } |
| | | const data = reactive({ |
| | | searchForm: { |
| | | staffName: "", |
| | | sysDeptId: undefined, |
| | | contractStartTime: undefined, |
| | | nation: undefined, |
| | | entryDate: undefined, // å½å
¥æ¥æ |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined, |
| | | }, |
| | | formatType: (params) => { |
| | | if (params == 0) { |
| | | return "danger"; |
| | | } else if (params == 1) { |
| | | return "primary"; |
| | | } else { |
| | | return null; |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | label: "åå·¥ç¼å·", |
| | | prop: "staffNo", |
| | | }, |
| | | { |
| | | label: "å§å", |
| | | prop: "staffName", |
| | | }, |
| | | { |
| | | label: "å«å", |
| | | prop: "alias", |
| | | }, |
| | | { |
| | | label: "ææº", |
| | | prop: "phone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "æ§å«", |
| | | prop: "sex", |
| | | }, |
| | | { |
| | | label: "åºçæ¥æ", |
| | | prop: "birthDate", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "å
¥èæ¥æ", |
| | | prop: "contractStartTime", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "è½¬æ£æ¥æ", |
| | | prop: "positiveDate", |
| | | width: 120, |
| | | dataType: "slot", |
| | | slot: "positiveDate", |
| | | }, |
| | | { |
| | | label: "å¹´é¾", |
| | | prop: "age", |
| | | }, |
| | | { |
| | | label: "ç±è´¯", |
| | | prop: "nativePlace", |
| | | }, |
| | | { |
| | | label: "æ°æ", |
| | | prop: "nation", |
| | | width: 100, |
| | | }, |
| | | { |
| | | label: "å©å§»ç¶åµ", |
| | | prop: "maritalStatus", |
| | | width: 100, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: 'right', |
| | | width: 180, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openFormNewOrEditFormDia("edit", row); |
| | | }, |
| | | deptOptions: [], |
| | | }); |
| | | const { searchForm, deptOptions } = toRefs(data); |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ç¶æ", |
| | | prop: "staffState", |
| | | dataType: "tag", |
| | | formatData: params => { |
| | | if (params == 0) { |
| | | return "离è"; |
| | | } else if (params == 1) { |
| | | return "å¨è"; |
| | | } else { |
| | | return null; |
| | | } |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0 |
| | | }); |
| | | const formDia = ref() |
| | | const formDiaNewOrEditFormDia = ref() |
| | | const { proxy } = getCurrentInstance() |
| | | formatType: params => { |
| | | if (params == 0) { |
| | | return "danger"; |
| | | } else if (params == 1) { |
| | | return "primary"; |
| | | } else { |
| | | return null; |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | label: "åå·¥ç¼å·", |
| | | prop: "staffNo", |
| | | }, |
| | | { |
| | | label: "å§å", |
| | | prop: "staffName", |
| | | }, |
| | | { |
| | | label: "å«å", |
| | | prop: "alias", |
| | | }, |
| | | { |
| | | label: "ææº", |
| | | prop: "phone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "æ§å«", |
| | | prop: "sex", |
| | | }, |
| | | { |
| | | label: "åºçæ¥æ", |
| | | prop: "birthDate", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "å
¥èæ¥æ", |
| | | prop: "contractStartTime", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "è½¬æ£æ¥æ", |
| | | prop: "positiveDate", |
| | | width: 120, |
| | | dataType: "slot", |
| | | slot: "positiveDate", |
| | | }, |
| | | { |
| | | label: "å¹´é¾", |
| | | prop: "age", |
| | | }, |
| | | { |
| | | label: "ç±è´¯", |
| | | prop: "nativePlace", |
| | | }, |
| | | { |
| | | label: "æ°æ", |
| | | prop: "nation", |
| | | width: 100, |
| | | formatData: params => { |
| | | return proxy.selectDictLabel(nation_type.value, params); |
| | | }, |
| | | }, |
| | | { |
| | | label: "å©å§»ç¶åµ", |
| | | prop: "maritalStatus", |
| | | width: 100, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 180, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openFormNewOrEditFormDia("edit", row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const formDia = ref(); |
| | | const formDiaNewOrEditFormDia = ref(); |
| | | const { proxy } = getCurrentInstance(); |
| | | const { nation_type } = proxy.useDict("nation_type"); |
| | | |
| | | // 导å
¥ç¸å
³ |
| | | const uploadRef = ref(null) |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå± |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/staff/staffOnJob/import" |
| | | }) |
| | | // 导å
¥ç¸å
³ |
| | | const uploadRef = ref(null); |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå± |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/staff/staffOnJob/import", |
| | | }); |
| | | |
| | | // å¤æè½¬æ£æ¥ææ¯å¦å¨7天å
|
| | | const getPositiveDateClass = (positiveDate) => { |
| | | if (!positiveDate) return ''; |
| | | const today = new Date(); |
| | | today.setHours(0, 0, 0, 0); |
| | | const positive = new Date(positiveDate); |
| | | positive.setHours(0, 0, 0, 0); |
| | | const diffTime = positive - today; |
| | | const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); |
| | | // 7天å
转æ£ï¼å
æ¬ä»å¤©ï¼æ¾ç¤ºè¦åè² |
| | | if (diffDays >= 0 && diffDays <= 7) { |
| | | return 'positive-date-warning'; |
| | | } |
| | | return ''; |
| | | }; |
| | | // å¤æè½¬æ£æ¥ææ¯å¦å¨7天å
|
| | | const getPositiveDateClass = positiveDate => { |
| | | if (!positiveDate) return ""; |
| | | const today = new Date(); |
| | | today.setHours(0, 0, 0, 0); |
| | | const positive = new Date(positiveDate); |
| | | positive.setHours(0, 0, 0, 0); |
| | | const diffTime = positive - today; |
| | | const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); |
| | | // 7天å
转æ£ï¼å
æ¬ä»å¤©ï¼æ¾ç¤ºè¦åè² |
| | | if (diffDays >= 0 && diffDays <= 7) { |
| | | return "positive-date-warning"; |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | const fetchDeptOptions = () => { |
| | | const fetchDeptOptions = () => { |
| | | deptTreeSelect().then(response => { |
| | | console.log(response.data) |
| | | console.log(response.data); |
| | | deptOptions.value = filterDisabledDept( |
| | | JSON.parse(JSON.stringify(response.data)) |
| | | ); |
| | | }); |
| | | }; |
| | | const filterDisabledDept = deptList => { |
| | | const filterDisabledDept = deptList => { |
| | | return deptList.filter(dept => { |
| | | if (dept.disabled) { |
| | | return false; |
| | |
| | | return true; |
| | | }); |
| | | }; |
| | | const changeDaterange = (value) => { |
| | | searchForm.value.entryDateStart = undefined; |
| | | searchForm.value.entryDateEnd = undefined; |
| | | if (value) { |
| | | searchForm.value.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD"); |
| | | searchForm.value.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD"); |
| | | } |
| | | getList(); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | fetchDeptOptions(); |
| | | tableLoading.value = true; |
| | | const params = { ...searchForm.value, ...page }; |
| | | params.entryDate = undefined |
| | | staffOnJobListPage({...params}).then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records |
| | | page.total = res.data.total; |
| | | }).catch(err => { |
| | | tableLoading.value = false; |
| | | }) |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | const changeDaterange = value => { |
| | | searchForm.value.entryDateStart = undefined; |
| | | searchForm.value.entryDateEnd = undefined; |
| | | if (value) { |
| | | searchForm.value.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD"); |
| | | searchForm.value.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD"); |
| | | } |
| | | getList(); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | fetchDeptOptions(); |
| | | tableLoading.value = true; |
| | | const params = { ...searchForm.value, ...page }; |
| | | params.entryDate = undefined; |
| | | staffOnJobListPage({ ...params }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }) |
| | | .catch(err => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | nextTick(() => { |
| | | formDia.value?.openDialog(type, row) |
| | | }) |
| | | }; |
| | | const openFormNewOrEditFormDia = (type, row) => { |
| | | nextTick(() => { |
| | | formDiaNewOrEditFormDia.value?.openDialog(type, row) |
| | | }) |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | nextTick(() => { |
| | | formDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | const openFormNewOrEditFormDia = (type, row) => { |
| | | nextTick(() => { |
| | | formDiaNewOrEditFormDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | batchDeleteStaffOnJobs(ids).then((res) => { |
| | | batchDeleteStaffOnJobs(ids).then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/staff/staffOnJob/export", {staffState: 1}, "åå·¥å°è´¦.xlsx"); |
| | | proxy.download( |
| | | "/staff/staffOnJob/export", |
| | | { staffState: 1 }, |
| | | "åå·¥å°è´¦.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | // 导å
¥æé®æä½ |
| | | const handleImport = () => { |
| | | upload.title = "å工导å
¥" |
| | | upload.open = true |
| | | } |
| | | // 导å
¥æé®æä½ |
| | | const handleImport = () => { |
| | | upload.title = "å工导å
¥"; |
| | | upload.open = true; |
| | | }; |
| | | |
| | | // ä¸è½½æ¨¡æ¿æä½ |
| | | const importTemplate = () => { |
| | | proxy.download("/staff/staffOnJob/downloadTemplate", {}, `å工导å
¥æ¨¡æ¿_${new Date().getTime()}.xlsx`) |
| | | } |
| | | // ä¸è½½æ¨¡æ¿æä½ |
| | | const importTemplate = () => { |
| | | proxy.download( |
| | | "/staff/staffOnJob/downloadTemplate", |
| | | {}, |
| | | `å工导å
¥æ¨¡æ¿_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | // æä»¶ä¸ä¼ ä¸å¤ç |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true |
| | | } |
| | | // æä»¶ä¸ä¼ ä¸å¤ç |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | // æä»¶ä¸ä¼ æåå¤ç |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.open = false |
| | | upload.isUploading = false |
| | | proxy.$refs["uploadRef"].handleRemove(file) |
| | | if (response.code !== 200) { |
| | | proxy.$modal.msgError(response.msg) |
| | | } else { |
| | | proxy.$modal.msgSuccess(response.msg) |
| | | } |
| | | getList() |
| | | } |
| | | // æä»¶ä¸ä¼ æåå¤ç |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.open = false; |
| | | upload.isUploading = false; |
| | | proxy.$refs["uploadRef"].handleRemove(file); |
| | | if (response.code !== 200) { |
| | | proxy.$modal.msgError(response.msg); |
| | | } else { |
| | | proxy.$modal.msgSuccess(response.msg); |
| | | } |
| | | getList(); |
| | | }; |
| | | |
| | | // æäº¤ä¸ä¼ æä»¶ |
| | | const submitFileForm = () => { |
| | | proxy.$refs["uploadRef"].submit() |
| | | } |
| | | // æäº¤ä¸ä¼ æä»¶ |
| | | const submitFileForm = () => { |
| | | proxy.$refs["uploadRef"].submit(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .search_title2 { |
| | | margin-left: 10px; |
| | | } |
| | | .search_title2 { |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | .positive-date-warning { |
| | | color: #f56c6c; |
| | | font-weight: bold; |
| | | } |
| | | .positive-date-warning { |
| | | color: #f56c6c; |
| | | font-weight: bold; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <FormDialog |
| | | v-model="dialogVisible" |
| | | :title="operationType === 'add' ? 'æ°å»ºå·¥èµè¡¨' : 'ç¼è¾å·¥èµè¡¨'" |
| | | width="90%" |
| | | @close="closeDia" |
| | | > |
| | | <FormDialog v-model="dialogVisible" |
| | | :title="operationType === 'add' ? 'æ°å»ºå·¥èµè¡¨' : 'ç¼è¾å·¥èµè¡¨'" |
| | | width="90%" |
| | | @close="closeDia"> |
| | | <template #footer> |
| | | <el-button type="info" @click="saveDraft">ä¿åè稿</el-button> |
| | | <el-button type="primary" @click="submitForm">确认æäº¤</el-button> |
| | | <el-button type="info" |
| | | @click="saveDraft">ä¿åè稿</el-button> |
| | | <el-button type="primary" |
| | | @click="submitForm">确认æäº¤</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </template> |
| | | <div class="form-dia-body"> |
| | | <!-- åºç¡èµæ --> |
| | | <el-card class="form-card" shadow="never"> |
| | | <el-card class="form-card" |
| | | shadow="never"> |
| | | <template #header> |
| | | <span class="card-title"><span class="card-title-line">|</span> åºç¡èµæ</span> |
| | | <el-icon class="card-collapse"><ArrowUp /></el-icon> |
| | | <el-icon class="card-collapse"> |
| | | <ArrowUp /> |
| | | </el-icon> |
| | | </template> |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-position="top"> |
| | | <el-form ref="formRef" |
| | | :model="form" |
| | | :rules="rules" |
| | | label-position="top"> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="å·¥èµä¸»é¢" prop="salaryTitle"> |
| | | <el-input |
| | | v-model="form.salaryTitle" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="20" |
| | | show-word-limit |
| | | /> |
| | | <el-form-item label="å·¥èµä¸»é¢" |
| | | prop="salaryTitle"> |
| | | <el-input v-model="form.salaryTitle" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | maxlength="20" |
| | | show-word-limit /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="éæ©é¨é¨" prop="deptIds"> |
| | | <el-select |
| | | v-model="form.deptIds" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | multiple |
| | | collapse-tags-tooltip |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in deptOptions" |
| | | :key="item.deptId" |
| | | :label="item.deptName" |
| | | :value="item.deptId" |
| | | /> |
| | | <el-form-item label="éæ©é¨é¨" |
| | | prop="deptIds"> |
| | | <el-select v-model="form.deptIds" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | multiple |
| | | collapse-tags-tooltip |
| | | style="width: 100%"> |
| | | <el-option v-for="item in deptOptions" |
| | | :key="item.deptId" |
| | | :label="item.deptName" |
| | | :value="item.deptId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="éæ©å·¥èµæä»½" prop="salaryMonth"> |
| | | <el-date-picker |
| | | v-model="form.salaryMonth" |
| | | type="month" |
| | | value-format="YYYY-MM" |
| | | format="YYYY-MM" |
| | | placeholder="è¯·éæ©å·¥èµæä»½" |
| | | style="width: 100%" |
| | | clearable |
| | | /> |
| | | <el-form-item label="éæ©å·¥èµæä»½" |
| | | prop="salaryMonth"> |
| | | <el-date-picker v-model="form.salaryMonth" |
| | | type="month" |
| | | value-format="YYYY-MM" |
| | | format="YYYY-MM" |
| | | placeholder="è¯·éæ©å·¥èµæä»½" |
| | | style="width: 100%" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input |
| | | v-model="form.remark" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | <el-form-item label="夿³¨" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="æ¯ä»é¶è¡" prop="payBank"> |
| | | <el-select |
| | | v-model="form.payBank" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="b in bankOptions" |
| | | :key="b" |
| | | :label="b" |
| | | :value="b" |
| | | /> |
| | | <el-form-item label="æ¯ä»é¶è¡" |
| | | prop="payBank"> |
| | | <el-select v-model="form.payBank" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | style="width: 100%"> |
| | | <el-option v-for="b in bankOptions" |
| | | :key="b" |
| | | :label="b" |
| | | :value="b" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="å®¡æ ¸äºº" prop="auditUserId"> |
| | | <el-select |
| | | v-model="form.auditUserId" |
| | | placeholder="è¯·éæ©å®¡æ ¸äºº" |
| | | clearable |
| | | filterable |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | /> |
| | | <el-form-item label="å®¡æ ¸äºº" |
| | | prop="auditUserId"> |
| | | <el-select v-model="form.auditUserId" |
| | | placeholder="è¯·éæ©å®¡æ ¸äºº" |
| | | clearable |
| | | filterable |
| | | style="width: 100%"> |
| | | <el-option v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.userId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </el-card> |
| | | |
| | | <!-- æä½æé® --> |
| | | <div class="toolbar"> |
| | | <el-button type="primary" @click="handleGenerate">çæå·¥èµè¡¨</el-button> |
| | | <el-button type="primary" |
| | | @click="handleGenerate">çæå·¥èµè¡¨</el-button> |
| | | <el-button @click="handleClear">æ¸
空</el-button> |
| | | <el-button @click="handleBatchDelete">å é¤</el-button> |
| | | <el-button @click="handleTaxForm">个ç¨è¡¨</el-button> |
| | | </div> |
| | | |
| | | <!-- å工工èµè¯¦æ
è¡¨æ ¼ --> |
| | | <div class="employee-table-wrap"> |
| | | <el-table |
| | | ref="employeeTableRef" |
| | | :data="employeeList" |
| | | border |
| | | max-height="400" |
| | | @selection-change="onEmployeeSelectionChange" |
| | | > |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="åå·¥å§å" prop="staffName" minWidth="100" /> |
| | | <el-table-column label="é¨é¨" prop="deptName" minWidth="100" /> |
| | | <el-table-column label="åºæ¬å·¥èµ" minWidth="110"> |
| | | <el-table ref="employeeTableRef" |
| | | :data="employeeList" |
| | | border |
| | | max-height="400" |
| | | @selection-change="onEmployeeSelectionChange"> |
| | | <el-table-column type="selection" |
| | | width="55" |
| | | align="center" /> |
| | | <el-table-column label="é¨é¨" |
| | | prop="deptName" |
| | | minWidth="120" /> |
| | | <el-table-column label="åå·¥å§å" |
| | | prop="staffName" |
| | | minWidth="100" /> |
| | | <el-table-column label="æ°æ" |
| | | prop="nation" |
| | | width="80" |
| | | align="center" /> |
| | | <el-table-column label="åºæ¬å·¥èµ" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.basicSalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.basicSalary = parseNum(row.basicSalary)" |
| | | /> |
| | | <el-input v-model.number="row.basicSalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.basicSalary = parseNum(row.basicSalary)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="计件工èµ" minWidth="110"> |
| | | <el-table-column label="ç½ç天æ°" |
| | | minWidth="100"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.pieceSalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.pieceSalary = parseNum(row.pieceSalary)" |
| | | /> |
| | | <el-input v-model.number="row.dayDays" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="handleDaysChange(row)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="计æ¶å·¥èµ" minWidth="110"> |
| | | <el-table-column label="å¤ç天æ°" |
| | | minWidth="100"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.hourlySalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.hourlySalary = parseNum(row.hourlySalary)" |
| | | /> |
| | | <el-input v-model.number="row.nightDays" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="handleDaysChange(row)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å
¶ä»æ¶å
¥" minWidth="110"> |
| | | <el-table-column label="é¤è¡¥" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.otherIncome" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.otherIncome = parseNum(row.otherIncome)" |
| | | /> |
| | | <el-input v-model.number="row.mealAmount" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | disabled /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="社ä¿ä¸ªäºº" minWidth="110"> |
| | | <el-table-column label="å¤çè¡¥å©" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.socialPersonal" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.socialPersonal = parseNum(row.socialPersonal)" |
| | | /> |
| | | <el-input v-model.number="row.nightAmount" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | disabled /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å
¬ç§¯é个人" minWidth="120"> |
| | | <el-table-column label="å
¶ä»æ¶å
¥" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.fundPersonal" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.fundPersonal = parseNum(row.fundPersonal)" |
| | | /> |
| | | <el-input v-model.number="row.otherIncome" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.otherIncome = parseNum(row.otherIncome)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å
¶ä»æ¯åº" minWidth="110"> |
| | | <el-table-column label="社ä¿ä¸ªäºº" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.otherDeduct" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.otherDeduct = parseNum(row.otherDeduct)" |
| | | /> |
| | | <el-input v-model.number="row.socialPersonal" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.socialPersonal = parseNum(row.socialPersonal)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å·¥èµä¸ªç¨" minWidth="110"> |
| | | <el-table-column label="å
¬ç§¯é个人" |
| | | minWidth="120"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.salaryTax" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.salaryTax = parseNum(row.salaryTax)" |
| | | /> |
| | | <el-input v-model.number="row.fundPersonal" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.fundPersonal = parseNum(row.fundPersonal)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºåå·¥èµ" minWidth="110"> |
| | | <el-table-column label="å
¶ä»æ¯åº" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.grossSalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.grossSalary = parseNum(row.grossSalary)" |
| | | /> |
| | | <el-input v-model.number="row.otherDeduct" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.otherDeduct = parseNum(row.otherDeduct)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºæ£å·¥èµ" minWidth="110"> |
| | | <el-table-column label="社ä¿è¡¥ç¼´" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.deductSalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.deductSalary = parseNum(row.deductSalary)" |
| | | /> |
| | | <el-input v-model.number="row.socialSecurityRetroactive" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.socialSecurityRetroactive = parseNum(row.socialSecurityRetroactive)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å®åå·¥èµ" minWidth="110"> |
| | | <el-table-column label="å·¥èµä¸ªç¨" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model.number="row.netSalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.netSalary = parseNum(row.netSalary)" |
| | | /> |
| | | <el-input v-model.number="row.salaryTax" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.salaryTax = parseNum(row.salaryTax)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="夿³¨" minWidth="120"> |
| | | <el-table-column label="åºåå·¥èµ" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input |
| | | v-model="row.remark" |
| | | placeholder="请è¾å
¥" |
| | | size="small" |
| | | /> |
| | | <el-input v-model.number="row.grossSalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.grossSalary = parseNum(row.grossSalary)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="80" align="center" fixed="right"> |
| | | <el-table-column label="åºæ£å·¥èµ" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-button type="primary" link @click="removeEmployee(row)">å é¤</el-button> |
| | | <el-input v-model.number="row.deductSalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.deductSalary = parseNum(row.deductSalary)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å®åå·¥èµ" |
| | | minWidth="110"> |
| | | <template #default="{ row }"> |
| | | <el-input v-model.number="row.netSalary" |
| | | type="number" |
| | | placeholder="0" |
| | | size="small" |
| | | @input="row.netSalary = parseNum(row.netSalary)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="夿³¨" |
| | | minWidth="120"> |
| | | <template #default="{ row }"> |
| | | <el-input v-model="row.remark" |
| | | placeholder="请è¾å
¥" |
| | | size="small" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" |
| | | width="80" |
| | | align="center" |
| | | fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button type="primary" |
| | | link |
| | | @click="removeEmployee(row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div v-if="!employeeList.length" class="table-empty">ææ æ°æ®</div> |
| | | <div v-else class="salary-total"> |
| | | <div v-if="!employeeList.length" |
| | | class="table-empty">ææ æ°æ®</div> |
| | | <div v-else |
| | | class="salary-total"> |
| | | <span class="total-label">å·¥èµæ»é¢ï¼</span> |
| | | <span class="total-value">Â¥ {{ totalSalary.toFixed(2) }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | |
| | | |
| | | <!-- æ°å¢äººåå¼¹çª --> |
| | | <el-dialog |
| | | v-model="addPersonVisible" |
| | | title="æ°å¢äººå" |
| | | width="400px" |
| | | append-to-body |
| | | @close="addPersonClose" |
| | | > |
| | | <el-dialog v-model="addPersonVisible" |
| | | title="æ°å¢äººå" |
| | | width="400px" |
| | | append-to-body |
| | | @close="addPersonClose"> |
| | | <div class="add-person-tree"> |
| | | <el-tree |
| | | ref="personTreeRef" |
| | | :data="deptStaffTree" |
| | | show-checkbox |
| | | node-key="id" |
| | | :props="{ label: 'label', children: 'children' }" |
| | | default-expand-all |
| | | /> |
| | | <el-tree ref="personTreeRef" |
| | | :data="deptStaffTree" |
| | | show-checkbox |
| | | node-key="id" |
| | | :props="{ label: 'label', children: 'children' }" |
| | | default-expand-all /> |
| | | </div> |
| | | <template #footer> |
| | | <el-button @click="addPersonVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="confirmAddPerson">ç¡®å®</el-button> |
| | | <el-button type="primary" |
| | | @click="confirmAddPerson">ç¡®å®</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 个ç¨è¡¨å¼¹çª --> |
| | | <el-dialog |
| | | v-model="taxDialogVisible" |
| | | title="个ç¨è¡¨" |
| | | width="700px" |
| | | append-to-body |
| | | > |
| | | <el-dialog v-model="taxDialogVisible" |
| | | title="个ç¨è¡¨" |
| | | width="700px" |
| | | append-to-body> |
| | | <div class="tax-desc">个人æå¾ç¨å
å¾é¢ï¼5000å
</div> |
| | | <el-table :data="taxTableData" border style="width: 100%;margin-bottom: 20px;"> |
| | | <el-table-column prop="level" label="级æ°" width="80" align="center" /> |
| | | <el-table-column |
| | | prop="range" |
| | | label="å
¨å¹´åºçº³ç¨æå¾é¢/å
" |
| | | min-width="220" |
| | | /> |
| | | <el-table-column |
| | | prop="rate" |
| | | label="ç¨ç(%)" |
| | | width="100" |
| | | align="center" |
| | | /> |
| | | <el-table-column |
| | | prop="quickDeduction" |
| | | label="éç®æ£é¤æ°/å
" |
| | | width="160" |
| | | align="center" |
| | | /> |
| | | <el-table :data="taxTableData" |
| | | border |
| | | style="width: 100%;margin-bottom: 20px;"> |
| | | <el-table-column prop="level" |
| | | label="级æ°" |
| | | width="80" |
| | | align="center" /> |
| | | <el-table-column prop="range" |
| | | label="å
¨å¹´åºçº³ç¨æå¾é¢/å
" |
| | | min-width="220" /> |
| | | <el-table-column prop="rate" |
| | | label="ç¨ç(%)" |
| | | width="100" |
| | | align="center" /> |
| | | <el-table-column prop="quickDeduction" |
| | | label="éç®æ£é¤æ°/å
" |
| | | width="160" |
| | | align="center" /> |
| | | </el-table> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs, computed, getCurrentInstance, nextTick } from "vue"; |
| | | import { ArrowUp } from "@element-plus/icons-vue"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { listDept } from "@/api/system/dept.js"; |
| | | import { staffOnJobList } from "@/api/personnelManagement/monthlyStatistics.js"; |
| | | import { bankList } from "@/api/personnelManagement/bank.js"; |
| | | import { |
| | | staffSalaryMainAdd, |
| | | staffSalaryMainUpdate, |
| | | staffSalaryMainCalculateSalary, |
| | | } from "@/api/personnelManagement/staffSalaryMain.js"; |
| | | import { userListNoPageByTenantId } from "@/api/system/user.js"; |
| | | import { |
| | | ref, |
| | | reactive, |
| | | toRefs, |
| | | computed, |
| | | getCurrentInstance, |
| | | nextTick, |
| | | } from "vue"; |
| | | import { ArrowUp } from "@element-plus/icons-vue"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { listDept } from "@/api/system/dept.js"; |
| | | import { staffOnJobList } from "@/api/personnelManagement/monthlyStatistics.js"; |
| | | import { bankList } from "@/api/personnelManagement/bank.js"; |
| | | import { |
| | | staffSalaryMainAdd, |
| | | staffSalaryMainUpdate, |
| | | staffSalaryMainCalculateSalary, |
| | | } from "@/api/personnelManagement/staffSalaryMain.js"; |
| | | import { userListNoPageByTenantId } from "@/api/system/user.js"; |
| | | import { listSubsidyConfiguration } from "@/api/personnelManagement/subsidyConfig.js"; |
| | | |
| | | |
| | | const emit = defineEmits(["update:modelValue", "close"]); |
| | | const props = defineProps({ |
| | | modelValue: { type: Boolean, default: false }, |
| | | operationType: { type: String, default: "add" }, |
| | | row: { type: Object, default: () => ({}) }, |
| | | }); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const dialogVisible = computed({ |
| | | get: () => props.modelValue, |
| | | set: (val) => emit("update:modelValue", val), |
| | | }); |
| | | |
| | | const formRef = ref(null); |
| | | const employeeTableRef = ref(null); |
| | | const personTreeRef = ref(null); |
| | | const addPersonVisible = ref(false); |
| | | const taxDialogVisible = ref(false); |
| | | const deptOptions = ref([]); |
| | | const deptStaffTree = ref([]); |
| | | const employeeList = ref([]); |
| | | const selectedEmployees = ref([]); |
| | | const bankOptions = ref([]); |
| | | const userList = ref([]); |
| | | const taxTableData = ref([ |
| | | { level: 1, range: "ä¸è¶
è¿36000å
", rate: 3, quickDeduction: 0 }, |
| | | { level: 2, range: "è¶
è¿36000-144000å
", rate: 10, quickDeduction: 2520 }, |
| | | { level: 3, range: "è¶
è¿144000-300000å
", rate: 20, quickDeduction: 16920 }, |
| | | { level: 4, range: "è¶
è¿300000-420000å
", rate: 25, quickDeduction: 31920 }, |
| | | { level: 5, range: "è¶
è¿420000-660000å
", rate: 30, quickDeduction: 52920 }, |
| | | { level: 6, range: "è¶
è¿660000-960000å
", rate: 35, quickDeduction: 85920 }, |
| | | { level: 7, range: "è¶
è¿960000å
", rate: 45, quickDeduction: 181920 }, |
| | | ]); |
| | | |
| | | function parseNum(v) { |
| | | if (v === "" || v == null) return 0; |
| | | const n = Number(v); |
| | | return isNaN(n) ? 0 : n; |
| | | } |
| | | |
| | | // åºç¡èµæè¡¨å |
| | | const data = reactive({ |
| | | form: { |
| | | id: undefined, |
| | | salaryTitle: "", |
| | | deptIds: [], |
| | | salaryMonth: "", |
| | | remark: "", |
| | | payBank: "", |
| | | auditUserId: undefined, |
| | | }, |
| | | rules: { |
| | | salaryTitle: [{ required: true, message: "请è¾å
¥å·¥èµä¸»é¢", trigger: "blur" }], |
| | | deptIds: [{ required: true, message: "è¯·éæ©é¨é¨", trigger: "change" }], |
| | | salaryMonth: [{ required: true, message: "è¯·éæ©å·¥èµæä»½", trigger: "change" }], |
| | | auditUserId: [{ required: true, message: "è¯·éæ©å®¡æ ¸äºº", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | |
| | | // 计ç®å·¥èµæ»é¢ï¼ææåå·¥å®åå·¥èµä¹åï¼ |
| | | const totalSalary = computed(() => { |
| | | return employeeList.value.reduce((sum, e) => sum + parseNum(e.netSalary), 0); |
| | | }); |
| | | |
| | | // æ ¹æ®å®¡æ ¸äººIDè·åå®¡æ ¸äººåç§° |
| | | const auditUserName = computed(() => { |
| | | if (!form.value.auditUserId) return ""; |
| | | const user = userList.value.find(u => u.userId === form.value.auditUserId); |
| | | return user ? user.nickName : ""; |
| | | }); |
| | | |
| | | const loadBankOptions = () => { |
| | | return bankList().then((res) => { |
| | | const list = Array.isArray(res?.data) ? res.data : []; |
| | | bankOptions.value = list |
| | | .map((b) => (b?.bankName == null ? "" : String(b.bankName).trim())) |
| | | .filter((v) => v !== ""); |
| | | const emit = defineEmits(["update:modelValue", "close"]); |
| | | const props = defineProps({ |
| | | modelValue: { type: Boolean, default: false }, |
| | | operationType: { type: String, default: "add" }, |
| | | row: { type: Object, default: () => ({}) }, |
| | | }); |
| | | }; |
| | | |
| | | const loadUserList = () => { |
| | | return userListNoPageByTenantId().then((res) => { |
| | | userList.value = res.data || []; |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const dialogVisible = computed({ |
| | | get: () => props.modelValue, |
| | | set: val => emit("update:modelValue", val), |
| | | }); |
| | | }; |
| | | |
| | | // æå¹³åé¨é¨æ ä¾ä¸æä½¿ç¨ |
| | | function flattenDept(tree, list = []) { |
| | | if (!tree?.length) return list; |
| | | tree.forEach((node) => { |
| | | list.push({ deptId: node.deptId, deptName: node.deptName }); |
| | | if (node.children?.length) flattenDept(node.children, list); |
| | | const formRef = ref(null); |
| | | const employeeTableRef = ref(null); |
| | | const personTreeRef = ref(null); |
| | | const addPersonVisible = ref(false); |
| | | const taxDialogVisible = ref(false); |
| | | const deptOptions = ref([]); |
| | | const deptStaffTree = ref([]); |
| | | const employeeList = ref([]); |
| | | const selectedEmployees = ref([]); |
| | | const bankOptions = ref([]); |
| | | const userList = ref([]); |
| | | const subsidyStandard = ref({ |
| | | mealAmount: 0, |
| | | nightAmount: 0, |
| | | }); |
| | | return list; |
| | | } |
| | | |
| | | const loadDeptOptions = () => { |
| | | listDept().then((res) => { |
| | | const tree = res.data ?? []; |
| | | deptOptions.value = flattenDept(tree); |
| | | }); |
| | | }; |
| | | |
| | | // æå»º é¨é¨-äººå æ ï¼ç¨äºæ°å¢äººåå¼¹çªï¼ |
| | | const loadDeptStaffTree = () => { |
| | | Promise.all([listDept(), staffOnJobList()]).then(([deptRes, staffRes]) => { |
| | | const tree = deptRes.data ?? []; |
| | | const staffList = staffRes.data ?? []; |
| | | const deptMap = new Map(); |
| | | function walk(nodes) { |
| | | nodes.forEach((node) => { |
| | | deptMap.set(node.deptId, { |
| | | id: "dept_" + node.deptId, |
| | | deptId: node.deptId, |
| | | label: node.deptName, |
| | | type: "dept", |
| | | children: [], |
| | | }); |
| | | if (node.children?.length) walk(node.children); |
| | | }); |
| | | } |
| | | walk(tree); |
| | | staffList.forEach((s) => { |
| | | const deptId = s.deptId ?? s.dept_id; |
| | | const node = deptMap.get(deptId); |
| | | if (node) { |
| | | node.children.push({ |
| | | id: s.id ?? s.staffId, |
| | | staffId: s.id ?? s.staffId, |
| | | label: s.staffName ?? s.name, |
| | | type: "staff", |
| | | ...s, |
| | | }); |
| | | const loadSubsidyStandard = () => { |
| | | listSubsidyConfiguration().then(res => { |
| | | if (res.data && res.data.length > 0) { |
| | | subsidyStandard.value = { |
| | | mealAmount: res.data[0].mealAmount || 0, |
| | | nightAmount: res.data[0].nightAmount || 0, |
| | | }; |
| | | } |
| | | }); |
| | | deptStaffTree.value = Array.from(deptMap.values()).filter( |
| | | (n) => n.children && n.children.length > 0 |
| | | ); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | const openDialog = (type, row) => { |
| | | nextTick(() => { |
| | | loadDeptOptions(); |
| | | loadBankOptions(); |
| | | loadUserList(); |
| | | employeeList.value = []; |
| | | Object.assign(form.value, { |
| | | const handleDaysChange = row => { |
| | | row.dayDays = parseNum(row.dayDays); |
| | | row.nightDays = parseNum(row.nightDays); |
| | | |
| | | // å¤ç补贴计ç®ï¼å¤çå¤©æ° * æ å |
| | | row.nightAmount = row.nightDays * subsidyStandard.value.nightAmount; |
| | | |
| | | // é¤è¡¥è®¡ç®ï¼ä»
éåæï¼(ç½ç + å¤ç) * æ å |
| | | // 注æï¼nation å¯è½æ¯åå
¸å¼ï¼è¿éå设 "åæ" æ¯ç´æ¥åå¨çå符串æéè¦æ ¹æ®åå
¸å¤æ |
| | | // ä¹åç BasicInfoSection.vue 䏿°ææ¯ä¸ææ¡ï¼é常åå¨çæ¯åå
¸ç value æ label |
| | | // è¿éå
ç®å夿å
å« "å" åï¼æè
æ¨å¯ä»¥æ ¹æ®å
·ä½åå
¸å¼è°æ´ |
| | | if (row.nation && (row.nation === "åæ" || row.nation.includes("å"))) { |
| | | row.mealAmount = |
| | | (row.dayDays + row.nightDays) * subsidyStandard.value.mealAmount; |
| | | } else { |
| | | row.mealAmount = 0; |
| | | } |
| | | }; |
| | | const taxTableData = ref([ |
| | | { level: 1, range: "ä¸è¶
è¿36000å
", rate: 3, quickDeduction: 0 }, |
| | | { level: 2, range: "è¶
è¿36000-144000å
", rate: 10, quickDeduction: 2520 }, |
| | | { level: 3, range: "è¶
è¿144000-300000å
", rate: 20, quickDeduction: 16920 }, |
| | | { level: 4, range: "è¶
è¿300000-420000å
", rate: 25, quickDeduction: 31920 }, |
| | | { level: 5, range: "è¶
è¿420000-660000å
", rate: 30, quickDeduction: 52920 }, |
| | | { level: 6, range: "è¶
è¿660000-960000å
", rate: 35, quickDeduction: 85920 }, |
| | | { level: 7, range: "è¶
è¿960000å
", rate: 45, quickDeduction: 181920 }, |
| | | ]); |
| | | |
| | | function parseNum(v) { |
| | | if (v === "" || v == null) return 0; |
| | | const n = Number(v); |
| | | return isNaN(n) ? 0 : n; |
| | | } |
| | | |
| | | // åºç¡èµæè¡¨å |
| | | const data = reactive({ |
| | | form: { |
| | | id: undefined, |
| | | salaryTitle: "", |
| | | deptIds: [], |
| | |
| | | remark: "", |
| | | payBank: "", |
| | | auditUserId: undefined, |
| | | }, |
| | | rules: { |
| | | salaryTitle: [ |
| | | { required: true, message: "请è¾å
¥å·¥èµä¸»é¢", trigger: "blur" }, |
| | | ], |
| | | deptIds: [{ required: true, message: "è¯·éæ©é¨é¨", trigger: "change" }], |
| | | salaryMonth: [ |
| | | { required: true, message: "è¯·éæ©å·¥èµæä»½", trigger: "change" }, |
| | | ], |
| | | auditUserId: [ |
| | | { required: true, message: "è¯·éæ©å®¡æ ¸äºº", trigger: "change" }, |
| | | ], |
| | | }, |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | |
| | | // 计ç®å·¥èµæ»é¢ï¼ææåå·¥å®åå·¥èµä¹åï¼ |
| | | const totalSalary = computed(() => { |
| | | return employeeList.value.reduce((sum, e) => sum + parseNum(e.netSalary), 0); |
| | | }); |
| | | |
| | | // æ ¹æ®å®¡æ ¸äººIDè·åå®¡æ ¸äººåç§° |
| | | const auditUserName = computed(() => { |
| | | if (!form.value.auditUserId) return ""; |
| | | const user = userList.value.find(u => u.userId === form.value.auditUserId); |
| | | return user ? user.nickName : ""; |
| | | }); |
| | | |
| | | const loadBankOptions = () => { |
| | | return bankList().then(res => { |
| | | const list = Array.isArray(res?.data) ? res.data : []; |
| | | bankOptions.value = list |
| | | .map(b => (b?.bankName == null ? "" : String(b.bankName).trim())) |
| | | .filter(v => v !== ""); |
| | | }); |
| | | // ç¼è¾ï¼å表页已è¿åä¸»è¡¨åæ®µï¼è¿éåªååæ¾ï¼æç»ç±âçæå·¥èµè¡¨/计ç®å·¥èµâå¾å°ï¼ |
| | | if (type === "edit" && row?.id) { |
| | | form.value.id = row.id; |
| | | form.value.salaryTitle = row.salaryTitle ?? ""; |
| | | // deptIds å端æ¯å符串ï¼å¤ä¸ªç¨éå·åéï¼ï¼å½å表å仿¯åé deptId |
| | | form.value.deptIds = row.deptIds |
| | | ? String(row.deptIds).split(",").map((id) => Number(id.trim())).filter(Boolean) |
| | | : []; |
| | | form.value.salaryMonth = row.salaryMonth ?? ""; |
| | | form.value.remark = row.remark ?? ""; |
| | | form.value.payBank = row.payBank ?? ""; |
| | | form.value.auditUserId = row.auditUserId ?? undefined; |
| | | |
| | | // 妿æåå·¥æç»æ°æ®ï¼ç´æ¥åæ¾ |
| | | if (row.staffSalaryDetailList && row.staffSalaryDetailList.length > 0) { |
| | | employeeList.value = row.staffSalaryDetailList.map((e) => ({ |
| | | staffOnJobId: e.staffOnJobId ?? e.staffId ?? e.id, |
| | | id: e.staffOnJobId ?? e.staffId ?? e.id, |
| | | staffName: e.staffName ?? "", |
| | | postName: e.postName ?? "", |
| | | deptName: e.deptName ?? "", |
| | | basicSalary: parseNum(e.basicSalary), |
| | | pieceSalary: parseNum(e.pieceSalary), |
| | | hourlySalary: parseNum(e.hourlySalary), |
| | | otherIncome: parseNum(e.otherIncome), |
| | | socialPersonal: parseNum(e.socialPersonal), |
| | | fundPersonal: parseNum(e.fundPersonal), |
| | | otherDeduct: parseNum(e.otherDeduct), |
| | | salaryTax: parseNum(e.salaryTax), |
| | | grossSalary: parseNum(e.grossSalary), |
| | | deductSalary: parseNum(e.deductSalary), |
| | | netSalary: parseNum(e.netSalary), |
| | | remark: e.remark ?? "", |
| | | })); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const openAddPerson = () => { |
| | | loadDeptStaffTree(); |
| | | addPersonVisible.value = true; |
| | | nextTick(() => { |
| | | personTreeRef.value?.setCheckedKeys([]); |
| | | }); |
| | | }; |
| | | |
| | | const addPersonClose = () => {}; |
| | | |
| | | const confirmAddPerson = () => { |
| | | const tree = personTreeRef.value; |
| | | if (!tree) { |
| | | addPersonVisible.value = false; |
| | | return; |
| | | } |
| | | const checked = tree.getCheckedNodes(); |
| | | const staffNodes = checked.filter((n) => n.type === "staff"); |
| | | const existIds = new Set(employeeList.value.map((e) => e.staffId || e.id)); |
| | | staffNodes.forEach((node) => { |
| | | const id = node.staffId ?? node.id; |
| | | if (existIds.has(id)) return; |
| | | existIds.add(id); |
| | | employeeList.value.push({ |
| | | staffOnJobId: id, |
| | | id, |
| | | staffName: node.label, |
| | | postName: node.postName ?? node.post ?? "", |
| | | deptName: node.deptName ?? "", |
| | | basicSalary: 0, |
| | | pieceSalary: 0, |
| | | hourlySalary: 0, |
| | | otherIncome: 0, |
| | | socialPersonal: 0, |
| | | fundPersonal: 0, |
| | | otherDeduct: 0, |
| | | salaryTax: 0, |
| | | grossSalary: 0, |
| | | deductSalary: 0, |
| | | netSalary: 0, |
| | | remark: "", |
| | | }); |
| | | }); |
| | | addPersonVisible.value = false; |
| | | }; |
| | | |
| | | const removeEmployee = (row) => { |
| | | employeeList.value = employeeList.value.filter( |
| | | (e) => (e.staffOnJobId || e.id) !== (row.staffOnJobId || row.id) |
| | | ); |
| | | }; |
| | | |
| | | const onEmployeeSelectionChange = (selection) => { |
| | | selectedEmployees.value = selection; |
| | | }; |
| | | |
| | | const handleBatchDelete = () => { |
| | | if (!selectedEmployees.value?.length) { |
| | | proxy.$modal.msgWarning("请å
å¾éè¦å é¤çåå·¥"); |
| | | return; |
| | | } |
| | | const ids = new Set(selectedEmployees.value.map((e) => e.staffOnJobId || e.id)); |
| | | employeeList.value = employeeList.value.filter( |
| | | (e) => !ids.has(e.staffOnJobId || e.id) |
| | | ); |
| | | }; |
| | | |
| | | const handleGenerate = () => { |
| | | if (!form.value.deptIds?.length) { |
| | | proxy.$modal.msgWarning("请å
éæ©é¨é¨"); |
| | | return; |
| | | } |
| | | if (!form.value.salaryMonth) { |
| | | proxy.$modal.msgWarning("请å
éæ©å·¥èµæä»½"); |
| | | return; |
| | | } |
| | | const payload = { |
| | | ids: form.value.deptIds, |
| | | date: form.value.salaryMonth, |
| | | }; |
| | | staffSalaryMainCalculateSalary(payload).then((res) => { |
| | | const list = Array.isArray(res?.data) ? res.data : []; |
| | | if (!list.length) { |
| | | proxy.$modal.msgWarning("æªè®¡ç®å°å·¥èµæ°æ®"); |
| | | |
| | | const loadUserList = () => { |
| | | return userListNoPageByTenantId().then(res => { |
| | | userList.value = res.data || []; |
| | | }); |
| | | }; |
| | | |
| | | // æå¹³åé¨é¨æ ä¾ä¸æä½¿ç¨ |
| | | function flattenDept(tree, list = []) { |
| | | if (!tree?.length) return list; |
| | | tree.forEach(node => { |
| | | list.push({ deptId: node.deptId, deptName: node.deptName }); |
| | | if (node.children?.length) flattenDept(node.children, list); |
| | | }); |
| | | return list; |
| | | } |
| | | |
| | | const loadDeptOptions = () => { |
| | | listDept().then(res => { |
| | | const tree = res.data ?? []; |
| | | deptOptions.value = flattenDept(tree); |
| | | }); |
| | | }; |
| | | |
| | | // æå»º é¨é¨-äººå æ ï¼ç¨äºæ°å¢äººåå¼¹çªï¼ |
| | | const loadDeptStaffTree = () => { |
| | | Promise.all([listDept(), staffOnJobList()]).then(([deptRes, staffRes]) => { |
| | | const tree = deptRes.data ?? []; |
| | | const staffList = staffRes.data ?? []; |
| | | const deptMap = new Map(); |
| | | function walk(nodes) { |
| | | nodes.forEach(node => { |
| | | deptMap.set(node.deptId, { |
| | | id: "dept_" + node.deptId, |
| | | deptId: node.deptId, |
| | | label: node.deptName, |
| | | type: "dept", |
| | | children: [], |
| | | }); |
| | | if (node.children?.length) walk(node.children); |
| | | }); |
| | | } |
| | | walk(tree); |
| | | staffList.forEach(s => { |
| | | const deptId = s.deptId ?? s.dept_id; |
| | | const node = deptMap.get(deptId); |
| | | if (node) { |
| | | node.children.push({ |
| | | id: s.id ?? s.staffId, |
| | | staffId: s.id ?? s.staffId, |
| | | label: s.staffName ?? s.name, |
| | | type: "staff", |
| | | ...s, |
| | | }); |
| | | } |
| | | }); |
| | | deptStaffTree.value = Array.from(deptMap.values()).filter( |
| | | n => n.children && n.children.length > 0 |
| | | ); |
| | | }); |
| | | }; |
| | | |
| | | const openDialog = (type, row) => { |
| | | nextTick(() => { |
| | | loadDeptOptions(); |
| | | loadBankOptions(); |
| | | loadUserList(); |
| | | loadSubsidyStandard(); |
| | | employeeList.value = []; |
| | | Object.assign(form.value, { |
| | | id: undefined, |
| | | salaryTitle: "", |
| | | deptIds: [], |
| | | salaryMonth: "", |
| | | remark: "", |
| | | payBank: "", |
| | | auditUserId: undefined, |
| | | }); |
| | | // ç¼è¾ï¼å表页已è¿åä¸»è¡¨åæ®µï¼è¿éåªååæ¾ï¼æç»ç±âçæå·¥èµè¡¨/计ç®å·¥èµâå¾å°ï¼ |
| | | if (type === "edit" && row?.id) { |
| | | form.value.id = row.id; |
| | | form.value.salaryTitle = row.salaryTitle ?? ""; |
| | | // deptIds å端æ¯å符串ï¼å¤ä¸ªç¨éå·åéï¼ï¼å½å表å仿¯åé deptId |
| | | form.value.deptIds = row.deptIds |
| | | ? String(row.deptIds) |
| | | .split(",") |
| | | .map(id => Number(id.trim())) |
| | | .filter(Boolean) |
| | | : []; |
| | | form.value.salaryMonth = row.salaryMonth ?? ""; |
| | | form.value.remark = row.remark ?? ""; |
| | | form.value.payBank = row.payBank ?? ""; |
| | | form.value.auditUserId = row.auditUserId ?? undefined; |
| | | |
| | | // 妿æåå·¥æç»æ°æ®ï¼ç´æ¥åæ¾ |
| | | if (row.staffSalaryDetailList && row.staffSalaryDetailList.length > 0) { |
| | | employeeList.value = row.staffSalaryDetailList.map(e => ({ |
| | | staffOnJobId: e.staffOnJobId ?? e.staffId ?? e.id, |
| | | id: e.staffOnJobId ?? e.staffId ?? e.id, |
| | | staffName: e.staffName ?? "", |
| | | postName: e.postName ?? "", |
| | | deptName: e.deptName ?? "", |
| | | nation: e.nation ?? "", |
| | | basicSalary: parseNum(e.basicSalary), |
| | | dayDays: parseNum(e.dayDays ?? e.dayShiftDays), |
| | | nightDays: parseNum(e.nightDays ?? e.nightShiftDays), |
| | | mealAmount: parseNum(e.mealAmount ?? e.mealSubsidy), |
| | | nightAmount: parseNum(e.nightAmount ?? e.nightSubsidy), |
| | | otherIncome: parseNum(e.otherIncome), |
| | | socialPersonal: parseNum(e.socialPersonal), |
| | | fundPersonal: parseNum(e.fundPersonal), |
| | | otherDeduct: parseNum(e.otherDeduct), |
| | | socialSecurityRetroactive: parseNum(e.socialSecurityRetroactive), |
| | | salaryTax: parseNum(e.salaryTax), |
| | | grossSalary: parseNum(e.grossSalary), |
| | | deductSalary: parseNum(e.deductSalary), |
| | | netSalary: parseNum(e.netSalary), |
| | | remark: e.remark ?? "", |
| | | })); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const openAddPerson = () => { |
| | | loadDeptStaffTree(); |
| | | addPersonVisible.value = true; |
| | | nextTick(() => { |
| | | personTreeRef.value?.setCheckedKeys([]); |
| | | }); |
| | | }; |
| | | |
| | | const addPersonClose = () => {}; |
| | | |
| | | const confirmAddPerson = () => { |
| | | const tree = personTreeRef.value; |
| | | if (!tree) { |
| | | addPersonVisible.value = false; |
| | | return; |
| | | } |
| | | employeeList.value = list.map((e) => ({ |
| | | ...e, |
| | | staffOnJobId: e.staffOnJobId ?? e.staffId ?? e.id, |
| | | staffName: e.staffName, |
| | | postName: e.postName, |
| | | deptName: e.deptName, |
| | | basicSalary: parseNum(e.basicSalary), |
| | | pieceSalary: parseNum(e.pieceSalary), |
| | | hourlySalary: parseNum(e.hourlySalary), |
| | | otherIncome: parseNum(e.otherIncome), |
| | | socialPersonal: parseNum(e.socialPersonal), |
| | | fundPersonal: parseNum(e.fundPersonal), |
| | | otherDeduct: parseNum(e.otherDeduct), |
| | | salaryTax: parseNum(e.salaryTax), |
| | | grossSalary: parseNum(e.grossSalary), |
| | | deductSalary: parseNum(e.deductSalary), |
| | | netSalary: parseNum(e.netSalary), |
| | | remark: e.remark ?? "", |
| | | })); |
| | | proxy.$modal.msgSuccess("çææå"); |
| | | }); |
| | | }; |
| | | |
| | | const handleClear = () => { |
| | | proxy.$modal.confirm("ç¡®å®æ¸
空å½ååå·¥å表åï¼").then(() => { |
| | | employeeList.value = []; |
| | | }).catch(() => {}); |
| | | }; |
| | | |
| | | const handleTaxForm = () => { |
| | | taxDialogVisible.value = true; |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value?.validate((valid) => { |
| | | if (!valid) return; |
| | | saveData(3); // 确认æäº¤ï¼ç¶æä¸º3ï¼å¾
å®¡æ ¸ï¼ |
| | | }); |
| | | }; |
| | | |
| | | const saveDraft = () => { |
| | | formRef.value?.validate((valid) => { |
| | | if (!valid) return; |
| | | saveData(1); // ä¿åè稿ï¼ç¶æä¸º1ï¼èç¨¿ï¼ |
| | | }); |
| | | }; |
| | | |
| | | const saveData = (status) => { |
| | | const payload = { |
| | | id: form.value.id, |
| | | salaryTitle: form.value.salaryTitle, |
| | | deptIds: form.value.deptIds?.length ? form.value.deptIds.join(",") : "", |
| | | salaryMonth: form.value.salaryMonth, |
| | | remark: form.value.remark, |
| | | payBank: form.value.payBank, |
| | | auditUserId: form.value.auditUserId, |
| | | auditUserName: auditUserName.value, |
| | | totalSalary: totalSalary.value, |
| | | staffSalaryDetailList: employeeList.value.map((e) => ({ |
| | | staffOnJobId: e.staffOnJobId ?? e.staffId ?? e.id, |
| | | staffName: e.staffName, |
| | | postName: e.postName ?? "", |
| | | deptName: e.deptName ?? "", |
| | | basicSalary: parseNum(e.basicSalary), |
| | | pieceSalary: parseNum(e.pieceSalary), |
| | | hourlySalary: parseNum(e.hourlySalary), |
| | | otherIncome: parseNum(e.otherIncome), |
| | | socialPersonal: parseNum(e.socialPersonal), |
| | | fundPersonal: parseNum(e.fundPersonal), |
| | | otherDeduct: parseNum(e.otherDeduct), |
| | | salaryTax: parseNum(e.salaryTax), |
| | | grossSalary: parseNum(e.grossSalary), |
| | | deductSalary: parseNum(e.deductSalary), |
| | | netSalary: parseNum(e.netSalary), |
| | | remark: e.remark ?? "", |
| | | })), |
| | | const checked = tree.getCheckedNodes(); |
| | | const staffNodes = checked.filter(n => n.type === "staff"); |
| | | const existIds = new Set(employeeList.value.map(e => e.staffId || e.id)); |
| | | staffNodes.forEach(node => { |
| | | const id = node.staffId ?? node.id; |
| | | if (existIds.has(id)) return; |
| | | existIds.add(id); |
| | | employeeList.value.push({ |
| | | staffOnJobId: id, |
| | | id, |
| | | staffName: node.label, |
| | | postName: node.postName ?? node.post ?? "", |
| | | deptName: node.deptName ?? "", |
| | | nation: node.nation ?? "", |
| | | basicSalary: parseNum(node.basicSalary), |
| | | dayDays: 0, |
| | | nightDays: 0, |
| | | mealAmount: 0, |
| | | nightAmount: 0, |
| | | otherIncome: 0, |
| | | socialPersonal: 0, |
| | | fundPersonal: 0, |
| | | otherDeduct: 0, |
| | | socialSecurityRetroactive: 0, |
| | | salaryTax: 0, |
| | | grossSalary: 0, |
| | | deductSalary: 0, |
| | | netSalary: 0, |
| | | remark: "", |
| | | }); |
| | | }); |
| | | addPersonVisible.value = false; |
| | | }; |
| | | if (props.operationType === "add") { |
| | | staffSalaryMainAdd({ ...payload, status }).then(() => { |
| | | proxy.$modal.msgSuccess(status === 1 ? "è稿ä¿åæå" : "æäº¤æå"); |
| | | closeDia(); |
| | | }); |
| | | } else { |
| | | staffSalaryMainUpdate({ ...payload, status }).then(() => { |
| | | proxy.$modal.msgSuccess(status === 1 ? "è稿ä¿åæå" : "æäº¤æå"); |
| | | closeDia(); |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | const closeDia = () => { |
| | | dialogVisible.value = false; |
| | | emit("close"); |
| | | }; |
| | | const removeEmployee = row => { |
| | | employeeList.value = employeeList.value.filter( |
| | | e => (e.staffOnJobId || e.id) !== (row.staffOnJobId || row.id) |
| | | ); |
| | | }; |
| | | |
| | | defineExpose({ openDialog }); |
| | | const onEmployeeSelectionChange = selection => { |
| | | selectedEmployees.value = selection; |
| | | }; |
| | | |
| | | const handleBatchDelete = () => { |
| | | if (!selectedEmployees.value?.length) { |
| | | proxy.$modal.msgWarning("请å
å¾éè¦å é¤çåå·¥"); |
| | | return; |
| | | } |
| | | const ids = new Set(selectedEmployees.value.map(e => e.staffOnJobId || e.id)); |
| | | employeeList.value = employeeList.value.filter( |
| | | e => !ids.has(e.staffOnJobId || e.id) |
| | | ); |
| | | }; |
| | | |
| | | const handleGenerate = () => { |
| | | if (!form.value.deptIds?.length) { |
| | | proxy.$modal.msgWarning("请å
éæ©é¨é¨"); |
| | | return; |
| | | } |
| | | if (!form.value.salaryMonth) { |
| | | proxy.$modal.msgWarning("请å
éæ©å·¥èµæä»½"); |
| | | return; |
| | | } |
| | | const payload = { |
| | | ids: form.value.deptIds, |
| | | date: form.value.salaryMonth, |
| | | }; |
| | | staffSalaryMainCalculateSalary(payload).then(res => { |
| | | const list = Array.isArray(res?.data) ? res.data : []; |
| | | if (!list.length) { |
| | | proxy.$modal.msgWarning("æªè®¡ç®å°å·¥èµæ°æ®"); |
| | | return; |
| | | } |
| | | employeeList.value = list.map(e => ({ |
| | | ...e, |
| | | staffOnJobId: e.staffOnJobId ?? e.staffId ?? e.id, |
| | | staffName: e.staffName, |
| | | postName: e.postName, |
| | | deptName: e.deptName, |
| | | nation: e.nation ?? "", |
| | | basicSalary: parseNum(e.basicSalary), |
| | | dayDays: parseNum(e.dayDays ?? e.dayShiftDays), |
| | | nightDays: parseNum(e.nightDays ?? e.nightShiftDays), |
| | | mealAmount: parseNum(e.mealAmount ?? e.mealSubsidy), |
| | | nightAmount: parseNum(e.nightAmount ?? e.nightSubsidy), |
| | | otherIncome: parseNum(e.otherIncome), |
| | | socialPersonal: parseNum(e.socialPersonal), |
| | | fundPersonal: parseNum(e.fundPersonal), |
| | | otherDeduct: parseNum(e.otherDeduct), |
| | | socialSecurityRetroactive: parseNum(e.socialSecurityRetroactive), |
| | | salaryTax: parseNum(e.salaryTax), |
| | | grossSalary: parseNum(e.grossSalary), |
| | | deductSalary: parseNum(e.deductSalary), |
| | | netSalary: parseNum(e.netSalary), |
| | | remark: e.remark ?? "", |
| | | })); |
| | | proxy.$modal.msgSuccess("çææå"); |
| | | }); |
| | | }; |
| | | |
| | | const handleClear = () => { |
| | | proxy.$modal |
| | | .confirm("ç¡®å®æ¸
空å½ååå·¥å表åï¼") |
| | | .then(() => { |
| | | employeeList.value = []; |
| | | }) |
| | | .catch(() => {}); |
| | | }; |
| | | |
| | | const handleTaxForm = () => { |
| | | taxDialogVisible.value = true; |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value?.validate(valid => { |
| | | if (!valid) return; |
| | | saveData(3); // 确认æäº¤ï¼ç¶æä¸º3ï¼å¾
å®¡æ ¸ï¼ |
| | | }); |
| | | }; |
| | | |
| | | const saveDraft = () => { |
| | | formRef.value?.validate(valid => { |
| | | if (!valid) return; |
| | | saveData(1); // ä¿åè稿ï¼ç¶æä¸º1ï¼èç¨¿ï¼ |
| | | }); |
| | | }; |
| | | |
| | | const saveData = status => { |
| | | const payload = { |
| | | id: form.value.id, |
| | | salaryTitle: form.value.salaryTitle, |
| | | deptIds: form.value.deptIds?.length ? form.value.deptIds.join(",") : "", |
| | | salaryMonth: form.value.salaryMonth, |
| | | remark: form.value.remark, |
| | | payBank: form.value.payBank, |
| | | auditUserId: form.value.auditUserId, |
| | | auditUserName: auditUserName.value, |
| | | totalSalary: totalSalary.value, |
| | | staffSalaryDetailList: employeeList.value.map(e => ({ |
| | | staffOnJobId: e.staffOnJobId ?? e.staffId ?? e.id, |
| | | staffName: e.staffName, |
| | | postName: e.postName ?? "", |
| | | deptName: e.deptName ?? "", |
| | | nation: e.nation ?? "", |
| | | basicSalary: parseNum(e.basicSalary), |
| | | dayDays: parseNum(e.dayDays), |
| | | nightDays: parseNum(e.nightDays), |
| | | mealAmount: parseNum(e.mealAmount), |
| | | nightAmount: parseNum(e.nightAmount), |
| | | otherIncome: parseNum(e.otherIncome), |
| | | socialPersonal: parseNum(e.socialPersonal), |
| | | fundPersonal: parseNum(e.fundPersonal), |
| | | otherDeduct: parseNum(e.otherDeduct), |
| | | socialSecurityRetroactive: parseNum(e.socialSecurityRetroactive), |
| | | salaryTax: parseNum(e.salaryTax), |
| | | grossSalary: parseNum(e.grossSalary), |
| | | deductSalary: parseNum(e.deductSalary), |
| | | netSalary: parseNum(e.netSalary), |
| | | remark: e.remark ?? "", |
| | | })), |
| | | }; |
| | | if (props.operationType === "add") { |
| | | staffSalaryMainAdd({ ...payload, status }).then(() => { |
| | | proxy.$modal.msgSuccess(status === 1 ? "è稿ä¿åæå" : "æäº¤æå"); |
| | | closeDia(); |
| | | }); |
| | | } else { |
| | | staffSalaryMainUpdate({ ...payload, status }).then(() => { |
| | | proxy.$modal.msgSuccess(status === 1 ? "è稿ä¿åæå" : "æäº¤æå"); |
| | | closeDia(); |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | const closeDia = () => { |
| | | dialogVisible.value = false; |
| | | emit("close"); |
| | | }; |
| | | |
| | | defineExpose({ openDialog }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .form-dia-body { |
| | | padding: 0; |
| | | } |
| | | .card-title-line { |
| | | color: #f56c6c; |
| | | margin-right: 4px; |
| | | } |
| | | .form-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | .form-card :deep(.el-card__header) { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 12px 16px; |
| | | } |
| | | .card-title { |
| | | font-weight: 500; |
| | | } |
| | | .card-collapse { |
| | | color: #999; |
| | | cursor: pointer; |
| | | } |
| | | .toolbar { |
| | | margin-bottom: 16px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | } |
| | | .employee-table-wrap { |
| | | position: relative; |
| | | min-height: 120px; |
| | | } |
| | | .table-empty { |
| | | text-align: center; |
| | | padding: 24px; |
| | | color: #999; |
| | | font-size: 14px; |
| | | } |
| | | .add-person-tree { |
| | | max-height: 360px; |
| | | overflow-y: auto; |
| | | padding: 8px 0; |
| | | } |
| | | .tax-desc { |
| | | margin-bottom: 12px; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | .salary-total { |
| | | margin-top: 16px; |
| | | padding: 12px 16px; |
| | | background-color: #f5f7fa; |
| | | border-radius: 4px; |
| | | text-align: right; |
| | | font-size: 16px; |
| | | } |
| | | .salary-total .total-label { |
| | | color: #606266; |
| | | margin-right: 8px; |
| | | } |
| | | .salary-total .total-value { |
| | | color: #f56c6c; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | } |
| | | .form-dia-body { |
| | | padding: 0; |
| | | } |
| | | .card-title-line { |
| | | color: #f56c6c; |
| | | margin-right: 4px; |
| | | } |
| | | .form-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | .form-card :deep(.el-card__header) { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 12px 16px; |
| | | } |
| | | .card-title { |
| | | font-weight: 500; |
| | | } |
| | | .card-collapse { |
| | | color: #999; |
| | | cursor: pointer; |
| | | } |
| | | .toolbar { |
| | | margin-bottom: 16px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | } |
| | | .employee-table-wrap { |
| | | position: relative; |
| | | min-height: 120px; |
| | | } |
| | | .table-empty { |
| | | text-align: center; |
| | | padding: 24px; |
| | | color: #999; |
| | | font-size: 14px; |
| | | } |
| | | .add-person-tree { |
| | | max-height: 360px; |
| | | overflow-y: auto; |
| | | padding: 8px 0; |
| | | } |
| | | .tax-desc { |
| | | margin-bottom: 12px; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | .salary-total { |
| | | margin-top: 16px; |
| | | padding: 12px 16px; |
| | | background-color: #f5f7fa; |
| | | border-radius: 4px; |
| | | text-align: right; |
| | | font-size: 16px; |
| | | } |
| | | .salary-total .total-label { |
| | | color: #606266; |
| | | margin-right: 8px; |
| | | } |
| | | .salary-total .total-value { |
| | | color: #f56c6c; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container subsidy-config-container"> |
| | | <el-row :gutter="20"> |
| | | <!-- 左侧é
置表å --> |
| | | <el-col :span="16"> |
| | | <el-card class="config-card" |
| | | shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <div class="header-title"> |
| | | <el-icon class="header-icon"> |
| | | <Setting /> |
| | | </el-icon> |
| | | <span>补贴æ åé
ç½®</span> |
| | | </div> |
| | | <div class="header-ops"> |
| | | <el-button type="primary" |
| | | :loading="loading" |
| | | @click="submitForm"> |
| | | <el-icon> |
| | | <Check /> |
| | | </el-icon> ä¿åé
ç½® |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <el-form ref="formRef" |
| | | :model="form" |
| | | :rules="rules" |
| | | label-position="top" |
| | | class="subsidy-form"> |
| | | <div class="config-section"> |
| | | <div class="section-title"> |
| | | <el-icon> |
| | | <Food /> |
| | | </el-icon> é¤è¡¥è®¾ç½® |
| | | </div> |
| | | <el-row :gutter="40"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="补贴æ åéé¢" |
| | | style="margin-right:20px" |
| | | prop="mealAmount"> |
| | | <el-input-number v-model="form.mealAmount" |
| | | :precision="2" |
| | | :step="1" |
| | | :min="0" |
| | | controls-position="right" |
| | | class="full-width-input" /> |
| | | <span class="input-unit">å
/天</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="quick-info"> |
| | | <div class="info-item"> |
| | | <span class="label">éç¨å¯¹è±¡ï¼</span> |
| | | <el-tag size="small" |
| | | type="warning">åæåå·¥</el-tag> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">计ç®èå´ï¼</span> |
| | | <span>ç½ç + å¤ç</span> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <el-divider /> |
| | | <div class="config-section"> |
| | | <div class="section-title"> |
| | | <el-icon> |
| | | <Moon /> |
| | | </el-icon> å¤çè¡¥å©è®¾ç½® |
| | | </div> |
| | | <el-row :gutter="40"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è¡¥å©æ åéé¢" |
| | | style="margin-right:20px" |
| | | prop="nightAmount"> |
| | | <el-input-number v-model="form.nightAmount" |
| | | :precision="2" |
| | | :step="1" |
| | | :min="0" |
| | | controls-position="right" |
| | | class="full-width-input" /> |
| | | <span class="input-unit">å
/天</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="quick-info"> |
| | | <div class="info-item"> |
| | | <span class="label">éç¨å¯¹è±¡ï¼</span> |
| | | <el-tag size="small">å
¨åï¼æç为å¤çï¼</el-tag> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">计ç®èå´ï¼</span> |
| | | <span>ä»
éå¤ç</span> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </el-form> |
| | | </el-card> |
| | | <!-- 计ç®ç¤ºä¾å¡ç --> |
| | | <el-card class="example-card" |
| | | shadow="never"> |
| | | <template #header> |
| | | <div class="card-header-small"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | <span>èªèµè®¡ç®é»è¾è¯´æ</span> |
| | | </div> |
| | | </template> |
| | | <div class="example-content"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <div class="example-box meal"> |
| | | <h5>é¤è¡¥è®¡ç®ç¤ºä¾</h5> |
| | | <p>è¥æ å为 <strong>{{ form.mealAmount }}å
/天</strong></p> |
| | | <p>æåæåå·¥ï¼ç½ç10天ï¼å¤ç10天</p> |
| | | <div class="formula"> |
| | | 计ç®ï¼(10 + 10) * {{ form.mealAmount }} = <span>{{ (20 * form.mealAmount).toFixed(2) }}å
</span> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="example-box night"> |
| | | <h5>å¤çè¡¥å©è®¡ç®ç¤ºä¾</h5> |
| | | <p>è¥æ å为 <strong>{{ form.nightAmount }}å
/天</strong></p> |
| | | <p>æåå·¥ï¼å½æå¤ç10天</p> |
| | | <div class="formula"> |
| | | 计ç®ï¼10 * {{ form.nightAmount }} = <span>{{ (10 * form.nightAmount).toFixed(2) }}å
</span> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <!-- å³ä¾§è§å说æ --> |
| | | <el-col :span="8"> |
| | | <el-card class="rule-card" |
| | | shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>ä¸å¡è§å详æ
</span> |
| | | </div> |
| | | </template> |
| | | <el-scrollbar height="500px"> |
| | | <div class="rule-item"> |
| | | <div class="rule-header"> |
| | | <span class="dot warning"></span> |
| | | <h6>å
³äºé¤è¡¥çæ åä¸åæ¾</h6> |
| | | </div> |
| | | <p>1. ç³»ç»å°èªå¨è¯å«å工档æ¡ä¸çãæ°æãåæ®µï¼ä»
å¯¹æ æ³¨ä¸ºâåæâçåå·¥è®¡ç®æ¤é¡¹è¡¥è´´ã</p> |
| | | <p>2. 忾便®ä»¥èå¤ç³»ç»ä¸çå®é
åºå¤å¤©æ°ä¸ºåï¼å
å«æææ£å¸¸çæ¬¡ï¼ç½çãå¤çï¼ã</p> |
| | | <p>3. 请åãæ·å·¥çéåºå¤å¤©æ°ä¸è®¡å
¥è®¡ç®èå´ã</p> |
| | | </div> |
| | | <el-divider /> |
| | | <div class="rule-item"> |
| | | <div class="rule-header"> |
| | | <span class="dot primary"></span> |
| | | <h6>å
³äºå¤çè¡¥å©çæ åä¸åæ¾</h6> |
| | | </div> |
| | | <p>1. åªè¦åå·¥çæççæ¬¡è¢«å®ä¹ä¸ºâå¤çâï¼ä¸æå®é
åºå¤è®°å½ï¼å³å¯äº«åæ¤è¡¥å©ã</p> |
| | | <p>2. è¡¥å©æå¤©è®¡ç®ï¼ä¸åºåå²ä½è级ï¼ç»ä¸æ§è¡æ¤æ åé
ç½®ã</p> |
| | | <p>3. æ¤è¡¥å©ä¸é¤è¡¥å¯åæ¶äº«åï¼è¥ç¬¦åé¤è¡¥æ¡ä»¶ï¼ã</p> |
| | | </div> |
| | | <el-alert title="é
ç½®çæè¯´æ" |
| | | type="info" |
| | | :closable="false" |
| | | show-icon |
| | | style="margin-top: 20px"> |
| | | ä¿®æ¹åçæ åå°å¨ä¸ä¸æ¬¡æ§è¡âå·¥èµç»ç®â任塿¶æ£å¼çæï¼ä¸ä¼å½±åå·²ç»ç®çåå²èªèµæ°æ®ã |
| | | </el-alert> |
| | | </el-scrollbar> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup name="SubsidyConfig"> |
| | | import { ref, onMounted } from "vue"; |
| | | import { |
| | | Setting, |
| | | Check, |
| | | RefreshRight, |
| | | Food, |
| | | Moon, |
| | | InfoFilled, |
| | | } from "@element-plus/icons-vue"; |
| | | import { |
| | | listSubsidyConfiguration, |
| | | saveSubsidyConfiguration, |
| | | } from "@/api/personnelManagement/subsidyConfig.js"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | |
| | | const formRef = ref(null); |
| | | const loading = ref(false); |
| | | |
| | | const form = ref({ |
| | | id: undefined, |
| | | mealAmount: 0, |
| | | nightAmount: 0, |
| | | tenantId: undefined, |
| | | createTime: undefined, |
| | | }); |
| | | |
| | | const rules = { |
| | | mealAmount: [{ required: true, message: "请è¾å
¥é¤è¡¥æ å", trigger: "blur" }], |
| | | nightAmount: [ |
| | | { required: true, message: "请è¾å
¥å¤çè¡¥å©æ å", trigger: "blur" }, |
| | | ], |
| | | }; |
| | | |
| | | /** æ¥è¯¢é
ç½® */ |
| | | const getConfig = async () => { |
| | | try { |
| | | const res = await listSubsidyConfiguration(); |
| | | if (res.data && res.data.length > 0) { |
| | | const config = res.data[0]; |
| | | form.value = { |
| | | id: config.id, |
| | | mealAmount: config.mealAmount || 0, |
| | | nightAmount: config.nightAmount || 0, |
| | | tenantId: config.tenantId, |
| | | createTime: config.createTime, |
| | | }; |
| | | } |
| | | } catch (error) { |
| | | console.error("è·åé
置失败", error); |
| | | } |
| | | }; |
| | | |
| | | /** æäº¤è¡¨å */ |
| | | const submitForm = async () => { |
| | | if (!formRef.value) return; |
| | | |
| | | await formRef.value.validate(async valid => { |
| | | if (valid) { |
| | | loading.value = true; |
| | | try { |
| | | await saveSubsidyConfiguration(form.value); |
| | | ElMessage.success("æ åé
ç½®å·²æ´æ°"); |
| | | getConfig(); // éæ°å 载以è·åå¯è½çæ´æ°ï¼å¦idï¼ |
| | | } catch (error) { |
| | | console.error("ä¿å失败", error); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getConfig(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .subsidy-config-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: calc(100vh - 84px); |
| | | |
| | | .config-card { |
| | | margin-bottom: 20px; |
| | | border-radius: 8px; |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .header-title { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | |
| | | .header-icon { |
| | | margin-right: 8px; |
| | | color: #409eff; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .subsidy-form { |
| | | padding: 10px 20px; |
| | | |
| | | .config-section { |
| | | .section-title { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | font-size: 16px; |
| | | font-weight: 500; |
| | | margin-bottom: 20px; |
| | | color: #606266; |
| | | |
| | | .el-icon { |
| | | color: #409eff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .full-width-input { |
| | | width: 100% !important; |
| | | } |
| | | |
| | | .input-unit { |
| | | position: absolute; |
| | | right: -45px; |
| | | top: 0; |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .quick-info { |
| | | background: #fdf6ec; |
| | | border-radius: 4px; |
| | | padding: 15px; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | gap: 10px; |
| | | |
| | | .info-item { |
| | | font-size: 14px; |
| | | color: #666; |
| | | .label { |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .example-card { |
| | | background: #fff; |
| | | border: 1px dashed #dcdfe6; |
| | | |
| | | .card-header-small { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .example-box { |
| | | padding: 15px; |
| | | border-radius: 6px; |
| | | |
| | | h5 { |
| | | margin: 0 0 10px 0; |
| | | font-size: 14px; |
| | | color: #303133; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | font-size: 13px; |
| | | color: #606266; |
| | | } |
| | | |
| | | .formula { |
| | | margin-top: 10px; |
| | | padding-top: 10px; |
| | | border-top: 1px solid rgba(0, 0, 0, 0.05); |
| | | font-size: 13px; |
| | | font-weight: bold; |
| | | |
| | | span { |
| | | color: #f56c6c; |
| | | font-size: 16px; |
| | | } |
| | | } |
| | | |
| | | &.meal { |
| | | background-color: #f0f9eb; |
| | | } |
| | | &.night { |
| | | background-color: #ecf5ff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .rule-card { |
| | | height: 100%; |
| | | |
| | | .rule-item { |
| | | padding: 5px 0; |
| | | |
| | | .rule-header { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | margin-bottom: 10px; |
| | | |
| | | .dot { |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 50%; |
| | | &.warning { |
| | | background: #e6a23c; |
| | | } |
| | | &.primary { |
| | | background: #409eff; |
| | | } |
| | | } |
| | | |
| | | h6 { |
| | | margin: 0; |
| | | font-size: 15px; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | p { |
| | | font-size: 13px; |
| | | line-height: 1.8; |
| | | color: #606266; |
| | | margin: 5px 0 5px 16px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-divider--horizontal) { |
| | | margin: 24px 0; |
| | | } |
| | | </style> |