diff --git a/gear-ui3/package.json b/gear-ui3/package.json index cf06ebf..f7a0fec 100644 --- a/gear-ui3/package.json +++ b/gear-ui3/package.json @@ -22,6 +22,7 @@ "@vueuse/core": "13.3.0", "axios": "1.9.0", "clipboard": "2.0.11", + "dayjs": "^1.11.19", "echarts": "5.6.0", "element-plus": "2.9.9", "file-saver": "2.0.5", diff --git a/gear-ui3/pnpm-lock.yaml b/gear-ui3/pnpm-lock.yaml index 2eff8b3..6d7f9b8 100644 --- a/gear-ui3/pnpm-lock.yaml +++ b/gear-ui3/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: clipboard: specifier: 2.0.11 version: 2.0.11 + dayjs: + specifier: ^1.11.19 + version: 1.11.19 echarts: specifier: 5.6.0 version: 5.6.0 @@ -71,6 +74,9 @@ importers: vue-router: specifier: 4.5.1 version: 4.5.1(vue@3.5.16) + vue3-treeselect: + specifier: ^0.1.10 + version: 0.1.10(vue@3.5.16) vuedraggable: specifier: 4.1.0 version: 4.1.0(vue@3.5.16) @@ -911,8 +917,8 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - dayjs@1.11.13: - resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + dayjs@1.11.19: + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -2463,6 +2469,11 @@ packages: peerDependencies: vue: ^3.2.0 + vue3-treeselect@0.1.10: + resolution: {integrity: sha512-QawdAbzmlZ7T3uBdSU4FRnrnmcV0Q9Jrph5hUBQJcXmM9OZ8lULQo7O7YbKxkOyuDX9Yx2rGjs6L5FKcL1FeXA==} + peerDependencies: + vue: ^3.0.0 + vue@3.5.16: resolution: {integrity: sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==} peerDependencies: @@ -3245,7 +3256,7 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 - dayjs@1.11.13: {} + dayjs@1.11.19: {} debug@2.6.9: dependencies: @@ -3361,7 +3372,7 @@ snapshots: '@types/lodash-es': 4.17.12 '@vueuse/core': 9.13.0(vue@3.5.16) async-validator: 4.2.5 - dayjs: 1.11.13 + dayjs: 1.11.19 escape-html: 1.0.3 lodash: 4.17.21 lodash-es: 4.17.21 @@ -4972,6 +4983,10 @@ snapshots: '@vue/devtools-api': 6.6.4 vue: 3.5.16 + vue3-treeselect@0.1.10(vue@3.5.16): + dependencies: + vue: 3.5.16 + vue@3.5.16: dependencies: '@vue/compiler-dom': 3.5.16 diff --git a/gear-ui3/src/components/RawSelector/index.vue b/gear-ui3/src/components/RawSelector/index.vue index e69de29..614ee6a 100644 --- a/gear-ui3/src/components/RawSelector/index.vue +++ b/gear-ui3/src/components/RawSelector/index.vue @@ -0,0 +1,112 @@ + + + \ No newline at end of file diff --git a/gear-ui3/src/components/Renderer/Raw.vue b/gear-ui3/src/components/Renderer/Raw.vue index bd8ca2e..5492374 100644 --- a/gear-ui3/src/components/Renderer/Raw.vue +++ b/gear-ui3/src/components/Renderer/Raw.vue @@ -1,25 +1,49 @@ \ No newline at end of file diff --git a/gear-ui3/src/components/StickyDragContainer/index.vue b/gear-ui3/src/components/StickyDragContainer/index.vue new file mode 100644 index 0000000..3f45b88 --- /dev/null +++ b/gear-ui3/src/components/StickyDragContainer/index.vue @@ -0,0 +1,149 @@ + + + + + + \ No newline at end of file diff --git a/gear-ui3/src/utils/gear.js b/gear-ui3/src/utils/gear.js index 3de2d98..a4842cf 100644 --- a/gear-ui3/src/utils/gear.js +++ b/gear-ui3/src/utils/gear.js @@ -226,3 +226,21 @@ export function getNormalPath(p) { export function blobValidate(data) { return data.type !== 'application/json' } + +/** + * 格式化小数(兼容数字/字符串输入),去除末尾所有0,末尾仅余小数点则去除 + * @param {number|string} num - 输入值(数字/合法数字字符串,如123.4500、"99.000"、"66") + * @returns {string} 格式化后的字符串,非法输入返回空字符串 + */ +export function formatDecimal(num) { + // 1. 统一转字符串并去除首尾空格,兼容带空格的输入 + const str = String(num).trim(); + // 2. 合法性校验:仅匹配 正负整数/小数(拒绝非数字、科学计数法等非法输入) + const validReg = /^-?\d+(\.\d+)?$/; + if (!validReg.test(str)) { + return ''; // 非法输入返回空字符串,也可根据需求改为抛出错误 + } + // 3. 核心格式化:先去末尾0,再处理末尾孤立的小数点 + // 正则1:匹配小数点后有效数字+末尾0,保留有效数字(去0);正则2:去掉末尾仅存的小数点 + return str.replace(/(\.\d*?)0*$/, '$1').replace(/\.$/, ''); +} \ No newline at end of file diff --git a/gear-ui3/src/views/mat/components/bom.vue b/gear-ui3/src/views/mat/components/bom.vue index b8bc9de..a13d5fc 100644 --- a/gear-ui3/src/views/mat/components/bom.vue +++ b/gear-ui3/src/views/mat/components/bom.vue @@ -20,8 +20,16 @@ - - + + + + + + @@ -42,7 +50,7 @@ --> - + @@ -67,6 +75,9 @@ + + \ No newline at end of file diff --git a/gear-ui3/src/views/mat/components/charts/InOutCompareChart.vue b/gear-ui3/src/views/mat/components/charts/InOutCompareChart.vue new file mode 100644 index 0000000..c885c3c --- /dev/null +++ b/gear-ui3/src/views/mat/components/charts/InOutCompareChart.vue @@ -0,0 +1,112 @@ + + + + + \ No newline at end of file diff --git a/gear-ui3/src/views/mat/components/charts/StockTrendChart.vue b/gear-ui3/src/views/mat/components/charts/StockTrendChart.vue new file mode 100644 index 0000000..fe6fa80 --- /dev/null +++ b/gear-ui3/src/views/mat/components/charts/StockTrendChart.vue @@ -0,0 +1,103 @@ + + + + + \ No newline at end of file diff --git a/gear-ui3/src/views/mat/components/in.vue b/gear-ui3/src/views/mat/components/in.vue index cda6797..417b470 100644 --- a/gear-ui3/src/views/mat/components/in.vue +++ b/gear-ui3/src/views/mat/components/in.vue @@ -13,19 +13,6 @@ - - @@ -35,9 +22,21 @@ - - - + + + + + + + + + - - - + + + + + + + + + - - + + + + + + + + + + + + @@ -73,8 +95,8 @@ @click="handleUpdate(scope.row)">修改 删除 - 归零 + 完成 @@ -92,7 +114,9 @@ - + + + @@ -135,7 +159,8 @@ --> - + @@ -161,7 +186,7 @@
- +
@@ -172,9 +197,11 @@ import { listPurchase, getPurchase, delPurchase, addPurchase, updatePurchase } from "@/api/mat/purchase"; import { listPurchaseInDetail, addPurchaseInDetail } from "@/api/mat/purchaseInDetail"; import PurchaseInDetail from "@/views/mat/components/in.vue" +import RawSelector from '@/components/RawSelector/index.vue'; // 引入组件 import Raw from "@/components/Renderer/Raw.vue" import useUserStore from '@/store/modules/user' import { computed } from "vue"; +import { formatDecimal } from '@/utils/gear' // 采购的四个状态 // 1. 在途(刚创建的) @@ -197,10 +224,44 @@ const total = ref(0); const title = ref(""); const currentPurchaseId = ref(''); -const formatterTime = (time) => { - return proxy.parseTime(time, '{y}-{m}-{d}') +/** + * 截止日期格式化方法 + * @param {string/Date} deadline - 截止日期(支持YYYY-MM-DD字符串/Date对象) + * @param {number} status - 状态值 + * @returns {string} 格式化后的显示文本 + */ +const formatterTime = (deadline, status) => { + // 边界处理:截止日期为空时返回提示 + if (!deadline) return '无截止日期' + + // 统一转换为Date对象(兼容字符串格式) + const deadlineDate = new Date(deadline) + // 时间有效性校验:无效时间返回原数据 + if (isNaN(deadlineDate.getTime())) return deadline + + // 状态为2时:返回格式化的原截止日期(YYYY-MM-DD)+ 绿色样式(由css控制) + if (status === 2) { + const year = deadlineDate.getFullYear() + const month = String(deadlineDate.getMonth() + 1).padStart(2, '0') + const day = String(deadlineDate.getDate()).padStart(2, '0') + return `${year}-${month}-${day}` + } + + // 状态非2时:计算剩余天数并格式化显示 + // 获取当前时间(取当天0点,避免时分秒干扰天数计算) + const now = new Date() + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + // 计算时间差(毫秒),转换为天数(1天=86400000毫秒) + const timeDiff = deadlineDate.getTime() - today.getTime() + const dayDiff = Math.floor(timeDiff / 86400000) + + // 按天数分场景显示 + if (dayDiff > 0) return `剩余${dayDiff}天` + if (dayDiff === 0) return '今日截止' + return `已过期${Math.abs(dayDiff)}天` } + const data = reactive({ form: {}, queryParams: { @@ -362,10 +423,13 @@ function handleExport() { const inOpen = ref(false); const inForm = ref({}); +const maxInNum = ref(0); +const inDetailRef = ref(null); function handleIn(row) { inOpen.value = true; const inTime = proxy.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}') + maxInNum.value = row.inTransitNum; inForm.value = { detailId: null, @@ -388,6 +452,7 @@ function submitFormIn() { proxy.$modal.msgSuccess("新增成功"); inOpen.value = false; getList(); + inDetailRef.value?.getList(); }).finally(() => { buttonLoading.value = false; loading.value = false; @@ -400,5 +465,22 @@ function cancelIn() { inOpen.value = false; } +function handleZero(row) { + proxy.$modal.confirm('是否将采购单编号为"' + row.purchaseId + '"的计划数量设为与已收数量相同,且状态设为已完成?').then(function () { + loading.value = true; + return updatePurchase({ + purchaseId: row.purchaseId, + planNum: row.receivedNum, + status: 2, + }); + }).then(() => { + loading.value = true; + getList(); + proxy.$modal.msgSuccess("发货计划已归档"); + }).finally(() => { + loading.value = false; + }); +} + getList(); diff --git a/gear-ui3/src/views/mat/raw/index.vue b/gear-ui3/src/views/mat/raw/index.vue index baed83e..fabab6c 100644 --- a/gear-ui3/src/views/mat/raw/index.vue +++ b/gear-ui3/src/views/mat/raw/index.vue @@ -41,7 +41,7 @@ - + @@ -49,7 +49,16 @@ - + + + + + + + + + @@ -168,6 +180,9 @@ import { listMaterial, getMaterial, delMaterial, addMaterial, updateMaterial } from "@/api/mat/material"; import { addPurchaseInDetail } from "@/api/mat/purchaseInDetail"; import { addMaterialOut } from "@/api/mat/materialOut"; +import Price from "@/views/mat/components/price.vue"; +import RawSelector from "@/components/RawSelector/index.vue"; +import { formatDecimal } from '@/utils/gear' import useUserStore from '@/store/modules/user' @@ -191,6 +206,14 @@ const outForm = ref({}); const inOpen = ref(false); const outOpen = ref(false); +const currentMaterialId = ref(null); + +function handleRowClick(row) { + currentMaterialId.value = row.materialId; +} + +const priceHistoryList = ref([]); + const nickName = computed(() => userStore.nickName) @@ -367,6 +390,8 @@ function cancelIn() { inOpen.value = false; } +const priceRef = ref(null); + function submitFormIn() { loading.value = true; buttonLoading.value = true; @@ -374,6 +399,7 @@ function submitFormIn() { proxy.$modal.msgSuccess("新增成功"); inOpen.value = false; getList(); + priceRef.value.getListChart(); }).finally(() => { buttonLoading.value = false; loading.value = false;