| 2 天以前 | gongchunyi | ![]() |
| 2 天以前 | gaoluyang | ![]() |
| 2 天以前 | gaoluyang | ![]() |
| 2 天以前 | gongchunyi | ![]() |
| 2 天以前 | zhangwencui | ![]() |
| 2 天以前 | zhangwencui | ![]() |
| 2 天以前 | gaoluyang | ![]() |
| 2 天以前 | gaoluyang | ![]() |
| 2 天以前 | zhangwencui | ![]() |
| 2 天以前 | zhangwencui | ![]() |
| 2 天以前 | gaoluyang | ![]() |
| 2 天以前 | gaoluyang | ![]() |
| 2 天以前 | gongchunyi | ![]() |
| 2 天以前 | gongchunyi | ![]() |
| index.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/personnelManagement/attendanceRules.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/basicData/product/ImportExcel/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/fileManagement/document/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/personnelManagement/attendanceCheckin/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/procurementManagement/procurementInvoiceLedger/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/invoiceRegistration/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/salesLedger/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/salesQuotation/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
index.html
@@ -10,6 +10,10 @@ /> <link rel="icon" href="/favicon.ico" /> <title>%VITE_APP_TITLE%</title> <!-- é«å¾·å°å¾API --> <script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=6af5d2639adbbabf95eddfbf2bae5739"></script> <!-- é«å¾·å°å¾æç´¢æä»¶ --> <script type="text/javascript" src="https://webapi.amap.com/loca?v=2.0.0&key=6af5d2639adbbabf95eddfbf2bae5739"></script> <!--[if lt IE 11 ]><script> window.location.href = "/html/ie.html"; src/api/personnelManagement/attendanceRules.js
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,45 @@ import request from "@/utils/request"; // è·åæå¡è§åå表 export function getAttendanceRules(query) { return request({ url: "/personalAttendanceLocationConfig/listPage", method: "get", params: query, }); } // æ°å¢æå¡è§å export function addAttendanceRule(data) { return request({ url: "/personalAttendanceLocationConfig/add", method: "post", data, }); } // æ´æ°æå¡è§å export function updateAttendanceRule(data) { return request({ url: "/attendanceRules/update", method: "put", data, }); } // å 餿å¡è§å export function deleteAttendanceRule(ids) { return request({ url: `/personalAttendanceLocationConfig/del`, method: "delete", data: ids, }); } // è·åå个æå¡è§å详æ export function getAttendanceRuleDetail(id) { return request({ url: `/attendanceRules/detail/${id}`, method: "get", }); } src/views/basicData/product/ImportExcel/index.vue
@@ -70,7 +70,7 @@ const handleFileSuccess = (response) => { const { code, msg } = response; if (code == 200) { ElMessage({ message: "å¯¼å ¥æå", type: "success" }); ElMessage({ message: msg || "å¯¼å ¥æå", type: "success" }); upload.open = false; emits("uploadSuccess"); } else { src/views/fileManagement/document/index.vue
@@ -107,7 +107,6 @@ current: pagination.currentPage, size: pagination.pageSize, total: pagination.total, layout: 'total, sizes, prev, pager, next, jumper' }" @selection-change="handleSelectionChange" @pagination="handlePagination" @@ -1137,9 +1136,9 @@ // æå»ºæ¥è¯¢åæ° const query = { page: pagination.currentPage, current: pagination.currentPage, size: pagination.pageSize, documentClassificationId:currentId.value documentClassificationId: currentId.value }; const res = await getDocumentList(query); @@ -1166,9 +1165,10 @@ }; // å¤çå页åå const handlePagination = (current, size) => { pagination.currentPage = current; pagination.pageSize = size; const handlePagination = (payload) => { // PIMTable emit: { page, limit } pagination.currentPage = payload?.page || 1; pagination.pageSize = payload?.limit || pagination.pageSize; loadDocumentList(); }; src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,461 @@ <template> <el-dialog v-model="dialogVisible" :title="dialogTitle" width="700px" :close-on-click-modal="false"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px" class="mt8"> <!-- é¨é¨éæ© --> <el-form-item label="é¨é¨" prop="sysDeptId"> <el-tree-select v-model="form.sysDeptId" :data="deptOptions" :props="{ value: 'id', label: 'label', children: 'children' }" value-key="id" placeholder="è¯·éæ©é¨é¨" check-strictly style="width: 100%" :disabled="operationType === 'view'" /> </el-form-item> <!-- å°ç¹ä¿¡æ¯ --> <!-- <el-form-item label="å°ç¹åç§°" prop="locationName"> <el-input v-model="form.locationName" placeholder="请è¾å ¥å°ç¹åç§°" :disabled="operationType === 'view'" /> </el-form-item> --> <!-- æå¡èå´ --> <el-form-item label="æå¡èå´(m)" prop="radius"> <el-input-number v-model="form.radius" :min="10" :max="1000" :step="10" placeholder="请è¾å ¥æå¡èå´" :disabled="operationType === 'view'" /> </el-form-item> <!-- é«å¾·å°å¾éæ© --> <el-form-item label="æå¡ä½ç½®" prop="longitude"> <div class="map-container"> <div class="map-header" style="margin-bottom: 10px"> <el-button @click="getCurrentLocation"> <el-icon> <Position /> </el-icon> å½åä½ç½® </el-button> <span style="margin-left: 10px; color: #909399;font-size: 12px;">ç¹å»å°å¾éæ©ä½ç½®</span> </div> <div id="map-container" class="map" ref="mapContainer"></div> <div class="coordinates-info mt10"> <el-input v-model="form.longitude" readonly placeholder="ç»åº¦" style="width: 140px; margin-right: 10px" /> <el-input v-model="form.latitude" readonly placeholder="纬度" style="width: 140px; margin-right: 10px" /> <!-- <el-input v-model="form.locationName" placeholder="å°ç¹åç§°" style="width: calc(100% - 290px)" /> --> </div> </div> </el-form-item> <el-form-item label="å°ç¹åç§°" prop="locationName"> <el-input v-model="form.locationName" :disabled="operationType === 'view'" placeholder="请è¾å ¥å°ç¹åç§°" /> </el-form-item> <!-- ä¸ä¸çæ¶é´ --> <el-form-item label="ä¸çæ¶é´" prop="startAt"> <el-time-picker v-model="form.startAt" format="HH:mm" value-format="HH:mm" placeholder="è¯·éæ©ä¸çæ¶é´" :disabled="operationType === 'view'" /> </el-form-item> <el-form-item label="ä¸çæ¶é´" prop="endAt"> <el-time-picker v-model="form.endAt" format="HH:mm" value-format="HH:mm" placeholder="è¯·éæ©ä¸çæ¶é´" :disabled="operationType === 'view'" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogVisible = false">åæ¶</el-button> <el-button type="primary" @click="submitForm" v-if="operationType !== 'view'"> ç¡®å® </el-button> </span> </template> </el-dialog> </template> <script setup> import { ref, reactive, computed, watch, onMounted, nextTick } from "vue"; import { ElMessage } from "element-plus"; import { Position } from "@element-plus/icons-vue"; import { deptTreeSelect } from "@/api/system/user.js"; import { addAttendanceRule } from "@/api/personnelManagement/attendanceRules.js"; const props = defineProps({ modelValue: { type: Boolean, default: false, }, operationType: { type: String, default: "add", }, row: { type: Object, default: () => ({}), }, }); const emit = defineEmits(["update:modelValue", "close"]); const dialogVisible = computed({ get: () => props.modelValue, set: val => emit("update:modelValue", val), }); const dialogTitle = computed(() => { if (props.operationType === "add") return "æ°å¢æå¡è§å"; if (props.operationType === "edit") return "ç¼è¾æå¡è§å"; return "æ¥çæå¡è§å"; }); // è¡¨åæ°æ® const formRef = ref(); const form = reactive({ id: "", sysDeptId: "", locationName: "", longitude: "", latitude: "", radius: 100, startAt: "09:00", endAt: "18:00", }); // 表åéªè¯è§å const rules = { sysDeptId: [{ required: true, message: "è¯·éæ©é¨é¨", trigger: "change" }], locationName: [ { required: true, message: "请è¾å ¥å°ç¹åç§°", trigger: "blur" }, ], longitude: [{ required: true, message: "è¯·éæ©æå¡ä½ç½®", trigger: "blur" }], latitude: [{ required: true, message: "è¯·éæ©æå¡ä½ç½®", trigger: "blur" }], radius: [{ required: true, message: "请è¾å ¥æå¡èå´", trigger: "blur" }], startAt: [{ required: true, message: "è¯·éæ©ä¸çæ¶é´", trigger: "change" }], endAt: [{ required: true, message: "è¯·éæ©ä¸çæ¶é´", trigger: "change" }], }; // é¨é¨é项 const deptOptions = ref([]); // å°å¾ç¸å ³ const mapContainer = ref(null); let map = null; let marker = null; let circle = null; // è·åé¨é¨å表 const fetchDeptOptions = () => { deptTreeSelect().then(response => { deptOptions.value = filterDisabledDept( JSON.parse(JSON.stringify(response.data)) ); }); }; // è¿æ»¤ç¦ç¨çé¨é¨ const filterDisabledDept = deptList => { return deptList.filter(dept => { if (dept.disabled) { return false; } if (dept.children && dept.children.length) { dept.children = filterDisabledDept(dept.children); } return true; }); }; // åå§åå°å¾ const initMap = () => { nextTick(() => { if (window.AMap && mapContainer.value) { // åå§åå°å¾ map = new window.AMap.Map(mapContainer.value, { zoom: 16, center: [116.397428, 39.90923], // é»è®¤å京 }); // æ·»å æ§ä»¶ window.AMap.plugin(["AMap.ToolBar", "AMap.Scale"], function () { map.addControl(new window.AMap.ToolBar()); map.addControl(new window.AMap.Scale()); }); // æ·»å æ è®° marker = new window.AMap.Marker({ position: [116.397428, 39.90923], draggable: true, cursor: "move", title: "ææ½å®ä½", }); map.add(marker); // æ·»å åå½¢èå´ circle = new window.AMap.Circle({ center: [116.397428, 39.90923], radius: form.radius, strokeColor: "#3366FF", strokeOpacity: 0.8, strokeWeight: 2, fillColor: "#3366FF", fillOpacity: 0.2, }); map.add(circle); // ç嬿 è®°ææ½ marker.on("dragend", e => { const position = e.lnglat; const lng = position.getLng(); const lat = position.getLat(); form.longitude = lng; form.latitude = lat; updateCircle(position); }); // ç嬿 è®°ææ½å¼å§ marker.on("dragstart", () => { map.setDefaultCursor("move"); }); // ç嬿 è®°ææ½ç»æ marker.on("dragend", () => { map.setDefaultCursor("default"); }); // çå¬å°å¾ç¹å» map.on("click", e => { const position = e.lnglat; const lng = position.getLng(); const lat = position.getLat(); form.longitude = lng; form.latitude = lat; updateMarker(position); updateCircle(position); }); // å°è¯è·åå½åä½ç½®å¹¶è®¾ç½®ä¸ºå°å¾ä¸å¿ if (navigator.geolocation && !form.longitude && !form.latitude) { navigator.geolocation.getCurrentPosition( position => { console.log("è·åå°å½åä½ç½®:", position); const { longitude, latitude } = position.coords; const currentPosition = [longitude, latitude]; map.setCenter(currentPosition); updateMarker(currentPosition); updateCircle(currentPosition); form.longitude = longitude; form.latitude = latitude; }, error => { console.log("è·åä½ç½®å¤±è´¥ï¼ä½¿ç¨é»è®¤ä½ç½®"); } ); } else if (form.longitude && form.latitude) { // å¦æææ°æ®ï¼è®¾ç½®å°å°å¾ const position = [form.longitude, form.latitude]; map.setCenter(position); updateMarker(position); updateCircle(position); } } }); }; // æ´æ°æ è®°ä½ç½® const updateMarker = position => { if (marker) { marker.setPosition(position); } }; // æ´æ°åå½¢èå´ const updateCircle = position => { if (circle) { circle.setCenter(position); circle.setRadius(form.radius); } }; // è·åå½åä½ç½® const getCurrentLocation = () => { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( position => { const { longitude, latitude } = position.coords; form.longitude = longitude; form.latitude = latitude; if (map) { map.setCenter([longitude, latitude]); updateMarker([longitude, latitude]); updateCircle([longitude, latitude]); } // éå°çç¼ç è·åå°å if (window.AMap) { // å è½½Geocoderæä»¶ window.AMap.plugin("AMap.Geocoder", function () { const geocoder = new window.AMap.Geocoder(); geocoder.getAddress([longitude, latitude], (status, result) => { if (status === "complete" && result.regeocode) { form.locationName = result.regeocode.formattedAddress; } }); }); } }, error => { ElMessage.error("è·åä½ç½®å¤±è´¥ï¼è¯·æå¨éæ©"); } ); } else { ElMessage.error("æµè§å¨ä¸æ¯æå°çå®ä½"); } }; // çå¬åå¾åå watch( () => form.radius, newValue => { if (circle) { circle.setRadius(newValue); } } ); // çå¬å¼¹çªæ¾ç¤º watch( () => dialogVisible.value, newValue => { if (newValue) { // é置表å Object.assign(form, { id: "", sysDeptId: "", locationName: "", longitude: "", latitude: "", radius: 100, startAt: "09:00", endAt: "18:00", }); // 妿æ¯ç¼è¾ææ¥çï¼å¡«å æ°æ® if (props.operationType !== "add" && props.row.id) { // å¤çæ¶é´æ ¼å¼ï¼ç¡®ä¿æ¯HH:mmæ ¼å¼ const rowData = { ...props.row }; if (rowData.startAt && rowData.startAt.includes(":")) { rowData.startAt = rowData.startAt.split(":").slice(0, 2).join(":"); } if (rowData.endAt && rowData.endAt.includes(":")) { rowData.endAt = rowData.endAt.split(":").slice(0, 2).join(":"); } Object.assign(form, rowData); } // åå§åå°å¾ setTimeout(() => { initMap(); }, 100); } } ); // æäº¤è¡¨å const submitForm = () => { formRef.value.validate(valid => { if (valid) { const submitData = { ...form, // è½¬æ¢æ¶é´æ ¼å¼ï¼ç¡®ä¿åªä¿çæ¶åé¨å startAt: form.startAt ? `${form.startAt.split(":").slice(0, 2).join(":")}` : null, endAt: form.endAt ? `${form.endAt.split(":").slice(0, 2).join(":")}` : null, }; if (props.operationType === "add") { addAttendanceRule(submitData).then(() => { ElMessage.success("æ°å¢æå"); emit("close"); }); } else if (props.operationType === "edit") { addAttendanceRule(submitData).then(() => { ElMessage.success("æ´æ°æå"); emit("close"); }); } } }); }; // åå§å onMounted(() => { fetchDeptOptions(); }); </script> <style scoped lang="scss"> .map-container { width: 100%; } .map { width: 100%; height: 400px; border: 1px solid #e4e7ed; } .coordinates-info { display: flex; gap: 10px; } .coordinates-display { padding: 10px; background-color: #f5f7fa; border-radius: 4px; } .mt10 { margin-top: 10px; } .mt8 { margin-top: 8px; } </style> src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,293 @@ <template> <div class="app-container"> <!-- 页颿 é¢åæä½æé® --> <div class="page-header"> <div class="title">æå¡è§åé ç½®</div> <div class="actions"> <el-button type="primary" @click="openForm('add')"> <el-icon> <Plus /> </el-icon> æ°å¢è§å </el-button> </div> </div> <!-- æ¥è¯¢æ¡ä»¶ --> <!-- <el-form :model="searchForm" :inline="true" class="search-form mb16"> <el-form-item label="é¨é¨ï¼" prop="countId"> <el-tree-select v-model="searchForm.countId" :data="deptOptions" :props="{ value: 'id', label: 'label', children: 'children' }" value-key="id" placeholder="è¯·éæ©é¨é¨" check-strictly style="width: 200px" /> </el-form-item> <el-form-item label="å°ç¹ï¼" prop="locationName"> <el-input v-model="searchForm.locationName" placeholder="请è¾å ¥å°ç¹åç§°" clearable style="width: 200px" /> </el-form-item> <el-form-item> <el-button type="primary" @click="fetchData"> <el-icon> <Search /> </el-icon> æç´¢ </el-button> <el-button @click="resetSearch"> <el-icon> <Refresh /> </el-icon> éç½® </el-button> </el-form-item> </el-form> --> <!-- è§åå表 --> <el-card shadow="never" class="mb16"> <el-table :data="tableData" border v-loading="tableLoading" style="width: 100%" row-key="id"> <el-table-column type="index" label="åºå·" width="60" align="center" /> <el-table-column label="é¨é¨"> <template #default="scope"> {{ getDeptNameById(scope.row.sysDeptId) }} </template> </el-table-column> <el-table-column prop="locationName" label="å°ç¹åç§°" /> <el-table-column prop="longitude" label="ç»åº¦" /> <el-table-column prop="latitude" label="纬度" /> <el-table-column prop="radius" label="æå¡èå´(m)" /> <el-table-column prop="startAt" label="ä¸çæ¶é´"> <template #default="scope"> {{ scope.row.startAt }} </template> </el-table-column> <el-table-column prop="endAt" label="ä¸çæ¶é´"> <template #default="scope"> {{ scope.row.endAt }} </template> </el-table-column> <el-table-column label="æä½" width="180" fixed="right" align="center"> <template #default="scope"> <el-button type="primary" size="small" link @click="openForm('edit', scope.row)">ç¼è¾</el-button> <el-button type="danger" size="small" link @click="handleDelete(scope.row.id)">å é¤</el-button> </template> </el-table-column> </el-table> <pagination :total="page.total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" class="mt10" /> </el-card> <!-- æ°å¢/ç¼è¾è§åå¼¹çª --> <rule-form ref="ruleFormRef" v-model="dialogVisible" :operation-type="operationType" :row="currentRow" @close="dialogVisible = false; fetchData()" /> </div> </template> <script setup> import { ref, reactive, onMounted } from "vue"; import { ElMessage, ElMessageBox } from "element-plus"; import { Plus, Edit, Delete, Search, Refresh } from "@element-plus/icons-vue"; import Pagination from "@/components/Pagination/index.vue"; import RuleForm from "./components/form.vue"; import { deptTreeSelect } from "@/api/system/user.js"; import { getAttendanceRules, deleteAttendanceRule, } from "@/api/personnelManagement/attendanceRules.js"; const { proxy } = getCurrentInstance(); // è¡¨æ ¼æ°æ® const tableData = ref([]); const tableLoading = ref(false); // å页忰 const page = reactive({ current: 1, size: 10, total: 0, }); // æ¥è¯¢è¡¨å const searchForm = reactive({ countId: "", locationName: "", }); // é¨é¨é项 const deptOptions = ref([]); // å¼¹çªæ§å¶ const dialogVisible = ref(false); const operationType = ref("add"); const currentRow = ref({}); const ruleFormRef = ref(); // æ ¼å¼åæ¶é´ const formatTime = timestamp => { if (!timestamp) return ""; const date = new Date(timestamp); return `${String(date.getHours()).padStart(2, "0")}:${String( date.getMinutes() ).padStart(2, "0")}`; }; // è·åé¨é¨å表 const fetchDeptOptions = () => { deptTreeSelect().then(response => { deptOptions.value = filterDisabledDept( JSON.parse(JSON.stringify(response.data)) ); }); }; // è¿æ»¤ç¦ç¨çé¨é¨ const filterDisabledDept = deptList => { return deptList.filter(dept => { if (dept.disabled) { return false; } if (dept.children && dept.children.length) { dept.children = filterDisabledDept(dept.children); } return true; }); }; // æ ¹æ®é¨é¨IDæ¥æ¾é¨é¨åç§° const getDeptNameById = (deptId, deptList = deptOptions.value) => { for (const dept of deptList) { if (dept.id === deptId) { return dept.label; } if (dept.children && dept.children.length) { const name = getDeptNameById(deptId, dept.children); if (name) { return name; } } } return ""; }; // æ¥è¯¢è§åå表 const fetchData = () => { tableLoading.value = true; getAttendanceRules({ ...page, ...searchForm }) .then(res => { tableData.value = res.data.records; page.total = res.data.total; }) .finally(() => { tableLoading.value = false; }); }; // å页忴 const paginationChange = pagination => { page.current = pagination.page; page.size = pagination.limit; fetchData(); }; // éç½®æç´¢ const resetSearch = () => { searchForm.countId = ""; searchForm.locationName = ""; fetchData(); }; // æå¼è¡¨å const openForm = (type, row = {}) => { operationType.value = type; currentRow.value = row; dialogVisible.value = true; }; // å é¤è§å const handleDelete = id => { ElMessageBox.confirm("ç¡®å®è¦å é¤è¿æ¡è§ååï¼", "å é¤ç¡®è®¤", { confirmButtonText: "ç¡®å®", cancelButtonText: "åæ¶", type: "warning", }) .then(() => { deleteAttendanceRule([id]).then(() => { ElMessage.success("å 餿å"); fetchData(); }); }) .catch(() => { // åæ¶å é¤ }); }; // åå§å onMounted(() => { fetchDeptOptions(); fetchData(); }); </script> <style scoped lang="scss"> .page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; .title { font-size: 18px; font-weight: 600; } .actions { display: flex; gap: 10px; } } .mb16 { margin-bottom: 16px; } .mt10 { margin-top: 10px; } </style> src/views/personnelManagement/attendanceCheckin/index.vue
@@ -5,7 +5,8 @@ class="mb16"> <div class="attendance-header"> <div> <div class="title">æå¡ç¾å°</div> <div class="title">æå¡ç¾å° </div> <div class="sub-title">æ¯æä¸é®æå¡ï¼èªå¨è®°å½ä¸ä¸çæ¶é´</div> </div> <div class="attendance-actions"> @@ -341,13 +342,45 @@ }); }; // è·åå½åä½ç½® const getCurrentLocation = () => { return new Promise((resolve, reject) => { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( position => { const { longitude, latitude } = position.coords; resolve({ longitude, latitude }); }, error => { console.log("è·åä½ç½®å¤±è´¥:", error); reject(error); } ); } else { reject(new Error("æµè§å¨ä¸æ¯æå°çå®ä½")); } }); }; // æå¡ const handleCheckInOut = () => { createPersonalAttendanceRecord({}).then(res => { fetchData(); fetchTodayData(); ElMessage.success("æå¡æåï¼"); }); getCurrentLocation() .then(location => { createPersonalAttendanceRecord(location).then(res => { fetchData(); fetchTodayData(); ElMessage.success("æå¡æåï¼"); }); }) .catch(error => { // è·åä½ç½®å¤±è´¥æ¶ï¼ä»å 许æå¡ ElMessage.warning("è·åä½ç½®å¤±è´¥ï¼å°ä½¿ç¨é»è®¤ä½ç½®æå¡"); createPersonalAttendanceRecord({}).then(res => { fetchData(); fetchTodayData(); ElMessage.success("æå¡æåï¼"); }); }); }; onMounted(() => { src/views/procurementManagement/procurementInvoiceLedger/index.vue
@@ -237,21 +237,32 @@ } ); // 主表åè®¡æ¹æ³ const summarizeMainTable = (param) => { return proxy.summarizeTable( const sums = proxy.summarizeTable( param, [ "taxInclusiveTotalPrice", "ticketsAmount", "unTicketsPrice", "invoiceAmount", ], ["ticketsAmount", "unTicketsPrice", "invoiceAmount"], { ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° ticketsNum: { noDecimal: true }, futureTickets: { noDecimal: true }, } ); const keySet = new Set(); let taxInclusiveSum = 0; (param.data || []).forEach((row) => { const key = `${row.purchaseContractNumber ?? ""}\n${row.salesContractNo ?? ""}\n${row.productCategory ?? ""}\n${row.specificationModel ?? ""}`; if (keySet.has(key)) return; keySet.add(key); const val = Number(row.taxInclusiveTotalPrice); if (!isNaN(val)) taxInclusiveSum += val; }); const taxInclusiveIndex = (param.columns || []).findIndex( (c) => c.property === "taxInclusiveTotalPrice" ); if (taxInclusiveIndex !== -1) { sums[taxInclusiveIndex] = taxInclusiveSum.toFixed(2); } return sums; }; const handleSelectionChange = (val) => { src/views/salesManagement/invoiceRegistration/index.vue
@@ -30,7 +30,12 @@ <div class="flex justify-between"> <div></div> <div> <el-button type="primary" @click="openForm" style="margin-bottom: 8px"> <el-button type="primary" @click="openForm" style="margin-bottom: 8px" :disabled="!canInvoice" > å¼ç¥¨ç»è®° </el-button> </div> @@ -296,10 +301,14 @@ /> <el-table-column label="æ¬æ¬¡å¼ç¥¨æ°" prop="currentInvoiceNum" width="180"> <template #default="scope"> <el-input-number :step="0.1" :min="0" style="width: 100%" :precision="2" v-model="scope.row.currentInvoiceNum" @change="invoiceNumBlur(scope.row)" <el-input-number :step="0.1" :min="0" style="width: 100%" :precision="2" v-model="scope.row.currentInvoiceNum" @change="invoiceNumBlur(scope.row)" :disabled="isProductInvoiceDisabled(scope.row)" ></el-input-number> </template> </el-table-column> @@ -309,10 +318,14 @@ width="180" > <template #default="scope"> <el-input-number :step="0.01" :min="0" style="width: 100%" :precision="2" v-model="scope.row.currentInvoiceAmount" @change="invoiceAmountBlur(scope.row)" <el-input-number :step="0.01" :min="0" style="width: 100%" :precision="2" v-model="scope.row.currentInvoiceAmount" @change="invoiceAmountBlur(scope.row)" :disabled="isProductInvoiceDisabled(scope.row)" ></el-input-number> </template> </el-table-column> @@ -375,7 +388,7 @@ <script setup> import pagination from "@/components/PIMTable/Pagination.vue"; import FormDialog from '@/components/Dialog/FormDialog.vue'; import { onMounted, ref } from "vue"; import { onMounted, ref, computed } from "vue"; import { Search } from "@element-plus/icons-vue"; import { ElMessageBox } from "element-plus"; // import {userListNoPage} from "@/api/system/user.js"; @@ -450,6 +463,27 @@ const formattedInputNumber = (value) => { return value ? parseFloat(value).toFixed(2) : 0; }; // 夿æ¯å¦å¯ä»¥å¼ç¥¨ï¼åºäºéä¸çå°è´¦æ°æ®ï¼ const canInvoice = computed(() => { if (selectedRows.value.length === 0) { return false; } // æ£æ¥ææéä¸çå°è´¦ï¼åªè¦æä¸ä¸ªæªå¼ç¥¨éé¢å¤§äº0ï¼å°±å¯ä»¥å¼ç¥¨ return selectedRows.value.some(row => { const noInvoiceAmount = parseFloat(row.noInvoiceAmountTotal || 0); return noInvoiceAmount > 0; }); }); // 夿åä¸ªäº§åæ¯å¦å¯ä»¥å¼ç¥¨ const isProductInvoiceDisabled = (row) => { // æ£æ¥æªå¼ç¥¨éé¢åæªå¼ç¥¨æ°ï¼å¦æé½ä¸º0æå°äºçäº0ï¼åç¦ç¨ // ä¼å ä½¿ç¨ tempnoInvoiceAmount å tempNoInvoiceNumï¼åå§å¼ï¼ï¼å¦ææ²¡æåä½¿ç¨ noInvoiceAmount å originalNoInvoiceNum const noInvoiceAmount = parseFloat(row.tempnoInvoiceAmount || row.noInvoiceAmount || 0); const noInvoiceNum = parseFloat(row.tempNoInvoiceNum || row.originalNoInvoiceNum || row.noInvoiceNum || 0); return noInvoiceAmount <= 0 || noInvoiceNum <= 0; }; // æ¥è¯¢å表 @@ -579,6 +613,14 @@ productData.value = allProductData; // 对äºä¸è½å¼ç¥¨ç产åï¼å°å¼ç¥¨æ°åå¼ç¥¨éé¢è®¾ç½®ä¸º0 productData.value.forEach(item => { if (isProductInvoiceDisabled(item)) { item.currentInvoiceNum = 0; item.currentInvoiceAmount = 0; } }); dialogFormVisible.value = true; console.log("productData.value ", productData.value); }); src/views/salesManagement/salesLedger/index.vue
@@ -121,7 +121,7 @@ <el-table-column label="夿³¨" prop="remarks" width="200" show-overflow-tooltip /> <el-table-column fixed="right" label="æä½" min-width="100" align="center"> <template #default="scope"> <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">ç¼è¾</el-button> <el-button link type="primary" size="small" @click="openForm('edit', scope.row)" :disabled="!scope.row.isEdit">ç¼è¾</el-button> <!-- <el-button link type="primary" size="small" @click="openForm('view', scope.row)">详æ </el-button>--> <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">éä»¶</el-button> <!-- <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">åè´§</el-button>--> @@ -318,6 +318,15 @@ </template> </el-table-column> </el-table> <pagination v-show="quotationPage.total > 0" :total="quotationPage.total" layout="total, sizes, prev, pager, next, jumper" :page="quotationPage.current" :limit="quotationPage.size" @pagination="quotationPaginationChange" /> <template #footer> <el-button @click="quotationDialogVisible = false">å ³é</el-button> @@ -781,6 +790,12 @@ quotationNo: "", customer: "", }); // æ¥ä»·åå¼¹æ¡å页 const quotationPage = reactive({ current: 1, size: 10, total: 0, }); const selectedQuotation = ref(null); // åè´§ç¸å ³ @@ -1075,6 +1090,8 @@ const openQuotationDialog = async () => { if (operationType.value === "view") return; quotationDialogVisible.value = true; // æå¼å¼¹çªæ¶éç½®å页å°ç¬¬ä¸é¡µ quotationPage.current = 1; // å ç¡®ä¿å®¢æ·å表已å è½½ï¼ä¾¿äºåç»åå¡« customerId if (!customerOption.value || customerOption.value.length === 0) { try { @@ -1091,14 +1108,15 @@ quotationLoading.value = true; try { const params = { // å ¼å®¹å端å页忮µï¼è¿éæ²¿ç¨æ¥ä»·é¡µé¢å·²æå¯ç¨çåæ®µå½å currentPage: 1, pageSize: 100, // å端å页忮µï¼current / size current: quotationPage.current, size: quotationPage.size, ...quotationSearchForm, status: "éè¿", }; const res = await getQuotationList(params); quotationList.value = res?.data?.records || []; quotationPage.total = res?.data?.total || 0; } finally { quotationLoading.value = false; } @@ -1107,9 +1125,17 @@ const resetQuotationSearch = async () => { quotationSearchForm.quotationNo = ""; quotationSearchForm.customer = ""; quotationPage.current = 1; await fetchQuotationList(); }; // æ¥ä»·åå¼¹æ¡å页忢 const quotationPaginationChange = (obj) => { quotationPage.current = obj.page; quotationPage.size = obj.limit; fetchQuotationList(); }; // é䏿¥ä»·åååå¡«å°å°è´¦è¡¨å const applyQuotation = (row) => { if (!row) return; src/views/salesManagement/salesQuotation/index.vue
@@ -453,15 +453,6 @@ // 计ç®å±æ§ const filteredList = computed(() => { let list = quotationList.value if (searchForm.quotationNo) { list = list.filter(item => item.quotationNo.includes(searchForm.quotationNo)) } if (searchForm.customer) { list = list.filter(item => item.customer === searchForm.customer) } if (searchForm.status) { list = list.filter(item => item.status === searchForm.status) } return list }) @@ -480,6 +471,9 @@ searchForm.quotationNo = '' searchForm.customer = '' searchForm.status = '' // éç½®å°ç¬¬ä¸é¡µå¹¶éæ°æ¥è¯¢ pagination.currentPage = 1 handleSearch() } const handleAdd = async () => { @@ -848,10 +842,14 @@ const handleCurrentChange = (val) => { pagination.currentPage = val.page pagination.pageSize = val.limit // å页ååæ¶éæ°æ¥è¯¢å表 handleSearch() } const handleSearch = ()=>{ const params = { ...pagination, // å端å页忰ï¼current / size current: pagination.currentPage, size: pagination.pageSize, ...searchForm } getQuotationList(params).then(res=>{