From 8f9ff13bd611dea65751c6eebaccd4e292c4c0c6 Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期三, 11 二月 2026 17:29:47 +0800
Subject: [PATCH] feat: 已进行开票、回款操作的销售台账需限制不能编辑删除原有产品
---
src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue | 461 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 461 insertions(+), 0 deletions(-)
diff --git a/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue b/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
new file mode 100644
index 0000000..39eacda
--- /dev/null
+++ b/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>
\ No newline at end of file
--
Gitblit v1.9.3