From c453a6edcecc6a9a7efbf6ef40e729a774de95a2 Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Wed, 13 May 2026 09:46:30 +0800 Subject: [PATCH 01/12] =?UTF-8?q?feat(hfnf):=20=E9=87=8D=E6=9E=84=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E4=B8=BA=E5=85=A8=E5=B1=8FBI=E5=A4=A7=E5=B1=8F?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=E8=BD=AE=E6=92=AD=E5=92=8C=E6=BB=9A?= =?UTF-8?q?=E5=8A=A8=E5=8A=A8=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 深色科技感主题,全屏平铺无侧边栏 - 数据总量从接口实时获取,四工厂按比例分配 - ECharts柱状图和饼图(暗色主题) - 工厂数据轮播卡片(4秒切换,滑入动画) - 实时数据滚动列表 - 排行榜高亮联动轮播 - 实时时钟显示 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/api/model/hfnf.js | 4 +- src/views/fac_cal/hfnf_index.vue | 532 +++++++++++++++++++++++++++++-- 2 files changed, 514 insertions(+), 22 deletions(-) diff --git a/src/api/model/hfnf.js b/src/api/model/hfnf.js index 1e12772b..dab1212d 100644 --- a/src/api/model/hfnf.js +++ b/src/api/model/hfnf.js @@ -6,8 +6,8 @@ export default { name: "列表", req: async function(data){ return await http.post( - `${config.HOST_URL}/hfnf_api/mplogx/`, - // "http://10.0.11.52:5800/mplogx/", + // `${config.HOST_URL}/hfnf_api/mplogx/`, + "http://10.0.11.52:5800/mplogx/", data ); } diff --git a/src/views/fac_cal/hfnf_index.vue b/src/views/fac_cal/hfnf_index.vue index 3d880f26..57448129 100644 --- a/src/views/fac_cal/hfnf_index.vue +++ b/src/views/fac_cal/hfnf_index.vue @@ -1,31 +1,523 @@ + \ No newline at end of file + +const formatNumber = (n) => n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') +const formatCompact = (n) => { + if (n >= 1e8) return (n / 1e8).toFixed(2) + '亿' + if (n >= 1e4) return (n / 1e4).toFixed(0) + '万' + return n.toString() +} +const goDetail = () => router.push('/hfnf_mplogx') + +const updateClock = () => { + const d = new Date() + clock.value = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')} ${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}:${String(d.getSeconds()).padStart(2,'0')}` +} + +const initBarChart = () => { + if (!barChartRef.value) return + barChart = echarts.init(barChartRef.value) + barChart.setOption({ + backgroundColor: 'transparent', + tooltip: { + trigger: 'axis', + backgroundColor: 'rgba(10,22,40,0.95)', borderColor: 'rgba(64,158,255,0.3)', + textStyle: { color: '#e0e6ed' }, + formatter: (p) => `${p[0].name}
数据量:${formatNumber(p[0].value)} 条`, + }, + grid: { left: 10, right: 15, top: 25, bottom: 20, containLabel: true }, + xAxis: { + type: 'category', data: factories.value.map(f => f.name), + axisLabel: { color: '#5a7a9a', fontSize: 11 }, + axisLine: { lineStyle: { color: 'rgba(255,255,255,0.06)' } }, + axisTick: { show: false }, + }, + yAxis: { + type: 'value', + axisLabel: { color: '#3a5570', formatter: v => v >= 1e8 ? (v/1e8).toFixed(1)+'亿' : (v/1e4).toFixed(0)+'万' }, + splitLine: { lineStyle: { color: 'rgba(255,255,255,0.03)' } }, + axisLine: { show: false }, + }, + series: [{ + type: 'bar', barWidth: '50%', + data: factories.value.map((f, i) => ({ + value: f.count, + itemStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: colors[i] }, { offset: 1, color: colors[i] + '15' }, + ]), + borderRadius: [4, 4, 0, 0], + shadowColor: colors[i] + '30', shadowBlur: 10, + }, + })), + label: { show: true, position: 'top', formatter: p => formatCompact(p.value), color: '#8a9bb5', fontSize: 12, fontWeight: 600 }, + animationDuration: 1500, animationEasing: 'cubicOut', + }], + }) +} + +const initPieChart = () => { + if (!pieChartRef.value) return + pieChart = echarts.init(pieChartRef.value) + pieChart.setOption({ + backgroundColor: 'transparent', + tooltip: { + trigger: 'item', + backgroundColor: 'rgba(10,22,40,0.95)', borderColor: 'rgba(64,158,255,0.3)', + textStyle: { color: '#e0e6ed' }, + }, + legend: { + orient: 'vertical', right: 8, top: 'center', + textStyle: { fontSize: 11, color: '#5a7a9a' }, + icon: 'circle', itemWidth: 8, itemHeight: 8, + }, + series: [{ + type: 'pie', radius: ['44%', '72%'], center: ['38%', '50%'], + itemStyle: { borderRadius: 5, borderColor: '#0a1628', borderWidth: 3 }, + label: { formatter: '{d}%', fontSize: 11, color: '#5a7a9a' }, + labelLine: { length: 8, length2: 6, lineStyle: { color: 'rgba(255,255,255,0.1)' } }, + emphasis: { itemStyle: { shadowBlur: 20, shadowColor: 'rgba(0,0,0,0.5)' } }, + data: factories.value.map(f => ({ value: f.count, name: f.name, itemStyle: { color: f.color } })), + animationType: 'scale', animationEasing: 'elasticOut', animationDuration: 1500, + }], + }) +} + +const handleResize = () => { barChart?.resize(); pieChart?.resize() } + +onMounted(() => { + updateClock() + clockTimer = setInterval(updateClock, 1000) + genScrollData() + + // 轮播 + carouselTimer = setInterval(() => { + activeFactory.value = (activeFactory.value + 1) % 4 + }, 4000) + + // 滚动 + let scrollPos = 0 + scrollTimer = setInterval(() => { + scrollPos -= 1 + const rowH = 36, total = scrollData.value.length * rowH + if (Math.abs(scrollPos) >= total / 2) scrollPos = 0 + scrollY.value = scrollPos + }, 60) + + API.hfnf.mplogx.list.req({ page: 1, page_size: 1 }).then(res => { + totalCount.value = res.count + nextTick(() => { initBarChart(); initPieChart() }) + }) + window.addEventListener('resize', handleResize) +}) + +onBeforeUnmount(() => { + clearInterval(clockTimer) + clearInterval(carouselTimer) + clearInterval(scrollTimer) + window.removeEventListener('resize', handleResize) + barChart?.dispose(); pieChart?.dispose() +}) + + + From 27aa7532b478f835a9ee9c422086ea34d05507e9 Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Wed, 13 May 2026 09:46:43 +0800 Subject: [PATCH 02/12] =?UTF-8?q?feat(fac=5Fcal):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=80=9A=E7=94=A8=E7=A1=85=E9=85=B8=E7=9B=90=E6=B0=B4=E6=B3=A5?= =?UTF-8?q?=E7=94=9F=E4=BA=A7=E6=95=B0=E6=8D=AE=E6=A8=A1=E6=9D=BF=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 从Word文档提取两张标准表格数据 - 表一:生产工艺数据模板(分类合并单元格) - 表二:元数据元素内容和格式(10列详细定义) - 深蓝渐变标题横幅,深色表头样式 - 添加静态路由配置 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/config/route.js | 8 + src/views/fac_cal/cement_data_template.vue | 275 +++++++++++++++++++++ 2 files changed, 283 insertions(+) create mode 100644 src/views/fac_cal/cement_data_template.vue diff --git a/src/config/route.js b/src/config/route.js index 6ee83b9d..5e652bc8 100644 --- a/src/config/route.js +++ b/src/config/route.js @@ -123,6 +123,14 @@ const routes = [ }, component: "bigScreen/track", }, + { + name: "cement_data_template", + path: "/cement_data_template", + meta: { + title: "数据模板", + }, + component: "home/cement_data_template", + }, { name: "userCenter", path: "/usercenter", diff --git a/src/views/fac_cal/cement_data_template.vue b/src/views/fac_cal/cement_data_template.vue new file mode 100644 index 00000000..ab7764b4 --- /dev/null +++ b/src/views/fac_cal/cement_data_template.vue @@ -0,0 +1,275 @@ + + + + + From b5be1bbfec69f05876e7a0c9bf5706864b3fab7d Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Wed, 13 May 2026 10:03:18 +0800 Subject: [PATCH 03/12] =?UTF-8?q?feat(fac=5Fcal):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=A6=96=E9=A1=B5=E6=95=B0=E6=8D=AE=E6=80=BB=E8=A7=88=E5=8F=8A?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=95=B0=E6=8D=AE=E6=A0=87=E5=87=86=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. hfnf_index: 数据总量改为从接口实时获取,四个工厂按比例自动分配 2. cement_data_template: 去除表格标题中的"表一""表二"前缀 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/views/fac_cal/cement_data_template.vue | 4 +- src/views/fac_cal/hfnf_index.vue | 899 +++++++++++---------- 2 files changed, 486 insertions(+), 417 deletions(-) diff --git a/src/views/fac_cal/cement_data_template.vue b/src/views/fac_cal/cement_data_template.vue index ab7764b4..0bd2f1f7 100644 --- a/src/views/fac_cal/cement_data_template.vue +++ b/src/views/fac_cal/cement_data_template.vue @@ -7,7 +7,7 @@
-

表一 通用硅酸盐水泥生产工艺数据模板

+

通用硅酸盐水泥生产工艺数据模板

@@ -19,7 +19,7 @@
-

表二 元数据元素内容和格式

+

元数据元素内容和格式

diff --git a/src/views/fac_cal/hfnf_index.vue b/src/views/fac_cal/hfnf_index.vue index 57448129..fdb4b5e4 100644 --- a/src/views/fac_cal/hfnf_index.vue +++ b/src/views/fac_cal/hfnf_index.vue @@ -1,131 +1,171 @@ @@ -138,11 +178,13 @@ import API from '@/api' const router = useRouter() const barChartRef = ref(null) const pieChartRef = ref(null) -let barChart = null, pieChart = null -let clockTimer = null, carouselTimer = null, scrollTimer = null +let barChart = null +let pieChart = null -const colors = ['#409eff', '#00e0a1', '#f5a623', '#ff6b6b'] +const colors = ['#409eff', '#67c23a', '#e6a23c', '#f56c6c'] +const bgColors = ['#ecf5ff', '#f0f9eb', '#fdf6ec', '#fef0f0'] +// 各工厂基础比例 const baseFactories = [ { name: '合肥南方', ratio: 0.4382 }, { name: '中联万吨', ratio: 0.3081 }, @@ -151,93 +193,87 @@ const baseFactories = [ ] const totalCount = ref(0) -const activeFactory = ref(0) -const clock = ref('') -const scrollY = ref(0) -const scrollWrap = ref(null) const factories = computed(() => { const total = totalCount.value + // 前3个按比例取整,最后一个用总量减去前3个保证总和精确 const counts = baseFactories.map(f => Math.round(total * f.ratio)) - counts[3] = total - counts[0] - counts[1] - counts[2] + const sumFirst3 = counts[0] + counts[1] + counts[2] + counts[3] = total - sumFirst3 + return baseFactories.map((f, i) => ({ - name: f.name, count: counts[i], color: colors[i], + name: f.name, + count: counts[i], + color: colors[i], + bgColor: bgColors[i], percentage: total > 0 ? (counts[i] / total) * 100 : 0, })) }) -const formattedTotal = computed(() => formatNumber(totalCount.value).split('')) +const maxFactory = computed(() => { + if (factories.value.length === 0) return { name: '-', count: 0 } + return factories.value.reduce((a, b) => (a.count > b.count ? a : b)) +}) -// 模拟滚动数据 -const scrollData = ref([]) -const genScrollData = () => { - const rows = [] - for (let i = 0; i < 30; i++) { - const fi = Math.floor(Math.random() * 4) - const h = String(Math.floor(Math.random() * 24)).padStart(2, '0') - const m = String(Math.floor(Math.random() * 60)).padStart(2, '0') - rows.push({ - time: `${h}:${m}`, - factory: baseFactories[fi].name, - color: colors[fi], - count: Math.floor(Math.random() * 50000) + 10000, - }) - } - scrollData.value = rows +const formatNumber = (num) => { + return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') } -const formatNumber = (n) => n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') -const formatCompact = (n) => { - if (n >= 1e8) return (n / 1e8).toFixed(2) + '亿' - if (n >= 1e4) return (n / 1e4).toFixed(0) + '万' - return n.toString() -} -const goDetail = () => router.push('/hfnf_mplogx') - -const updateClock = () => { - const d = new Date() - clock.value = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')} ${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}:${String(d.getSeconds()).padStart(2,'0')}` +const goDetail = () => { + router.push('/hfnf_mplogx') } const initBarChart = () => { if (!barChartRef.value) return barChart = echarts.init(barChartRef.value) barChart.setOption({ - backgroundColor: 'transparent', tooltip: { trigger: 'axis', - backgroundColor: 'rgba(10,22,40,0.95)', borderColor: 'rgba(64,158,255,0.3)', - textStyle: { color: '#e0e6ed' }, - formatter: (p) => `${p[0].name}
数据量:${formatNumber(p[0].value)} 条`, + formatter: (params) => { + const p = params[0] + return `${p.name}
数据量:${formatNumber(p.value)} 条` + }, }, - grid: { left: 10, right: 15, top: 25, bottom: 20, containLabel: true }, + grid: { left: 20, right: 30, top: 20, bottom: 30, containLabel: true }, xAxis: { - type: 'category', data: factories.value.map(f => f.name), - axisLabel: { color: '#5a7a9a', fontSize: 11 }, - axisLine: { lineStyle: { color: 'rgba(255,255,255,0.06)' } }, + type: 'category', + data: factories.value.map((f) => f.name), + axisLabel: { color: '#666', fontSize: 13 }, + axisLine: { lineStyle: { color: '#e4e7ed' } }, axisTick: { show: false }, }, yAxis: { type: 'value', - axisLabel: { color: '#3a5570', formatter: v => v >= 1e8 ? (v/1e8).toFixed(1)+'亿' : (v/1e4).toFixed(0)+'万' }, - splitLine: { lineStyle: { color: 'rgba(255,255,255,0.03)' } }, - axisLine: { show: false }, + axisLabel: { + color: '#999', + formatter: (v) => (v >= 1e8 ? (v / 1e8).toFixed(1) + '亿' : (v / 1e4).toFixed(0) + '万'), + }, + splitLine: { lineStyle: { color: '#f0f0f0' } }, }, - series: [{ - type: 'bar', barWidth: '50%', - data: factories.value.map((f, i) => ({ - value: f.count, - itemStyle: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: colors[i] }, { offset: 1, color: colors[i] + '15' }, - ]), - borderRadius: [4, 4, 0, 0], - shadowColor: colors[i] + '30', shadowBlur: 10, + series: [ + { + type: 'bar', + data: factories.value.map((f) => ({ + value: f.count, + itemStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: f.color }, + { offset: 1, color: f.bgColor }, + ]), + borderRadius: [6, 6, 0, 0], + }, + })), + barWidth: '45%', + label: { + show: true, + position: 'top', + formatter: (p) => (p.value / 1e8).toFixed(2) + '亿', + color: '#333', + fontSize: 13, + fontWeight: 600, }, - })), - label: { show: true, position: 'top', formatter: p => formatCompact(p.value), color: '#8a9bb5', fontSize: 12, fontWeight: 600 }, - animationDuration: 1500, animationEasing: 'cubicOut', - }], + }, + ], }) } @@ -245,279 +281,312 @@ const initPieChart = () => { if (!pieChartRef.value) return pieChart = echarts.init(pieChartRef.value) pieChart.setOption({ - backgroundColor: 'transparent', tooltip: { trigger: 'item', - backgroundColor: 'rgba(10,22,40,0.95)', borderColor: 'rgba(64,158,255,0.3)', - textStyle: { color: '#e0e6ed' }, + formatter: (p) => `${p.name}
数据量:${formatNumber(p.value)}
占比:${p.percent}%`, }, legend: { - orient: 'vertical', right: 8, top: 'center', - textStyle: { fontSize: 11, color: '#5a7a9a' }, - icon: 'circle', itemWidth: 8, itemHeight: 8, + orient: 'vertical', + right: 10, + top: 'center', + textStyle: { fontSize: 13, color: '#666' }, }, - series: [{ - type: 'pie', radius: ['44%', '72%'], center: ['38%', '50%'], - itemStyle: { borderRadius: 5, borderColor: '#0a1628', borderWidth: 3 }, - label: { formatter: '{d}%', fontSize: 11, color: '#5a7a9a' }, - labelLine: { length: 8, length2: 6, lineStyle: { color: 'rgba(255,255,255,0.1)' } }, - emphasis: { itemStyle: { shadowBlur: 20, shadowColor: 'rgba(0,0,0,0.5)' } }, - data: factories.value.map(f => ({ value: f.count, name: f.name, itemStyle: { color: f.color } })), - animationType: 'scale', animationEasing: 'elasticOut', animationDuration: 1500, - }], + series: [ + { + type: 'pie', + radius: ['42%', '70%'], + center: ['40%', '50%'], + avoidLabelOverlap: true, + itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 3 }, + label: { + show: true, + formatter: '{b}\n{d}%', + fontSize: 12, + lineHeight: 18, + }, + labelLine: { length: 15, length2: 10 }, + emphasis: { + itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.2)' }, + }, + data: factories.value.map((f) => ({ + value: f.count, + name: f.name, + itemStyle: { color: f.color }, + })), + }, + ], }) } -const handleResize = () => { barChart?.resize(); pieChart?.resize() } +const handleResize = () => { + barChart?.resize() + pieChart?.resize() +} onMounted(() => { - updateClock() - clockTimer = setInterval(updateClock, 1000) - genScrollData() - - // 轮播 - carouselTimer = setInterval(() => { - activeFactory.value = (activeFactory.value + 1) % 4 - }, 4000) - - // 滚动 - let scrollPos = 0 - scrollTimer = setInterval(() => { - scrollPos -= 1 - const rowH = 36, total = scrollData.value.length * rowH - if (Math.abs(scrollPos) >= total / 2) scrollPos = 0 - scrollY.value = scrollPos - }, 60) - API.hfnf.mplogx.list.req({ page: 1, page_size: 1 }).then(res => { totalCount.value = res.count - nextTick(() => { initBarChart(); initPieChart() }) + nextTick(() => { + initBarChart() + initPieChart() + }) }) window.addEventListener('resize', handleResize) }) onBeforeUnmount(() => { - clearInterval(clockTimer) - clearInterval(carouselTimer) - clearInterval(scrollTimer) window.removeEventListener('resize', handleResize) - barChart?.dispose(); pieChart?.dispose() + barChart?.dispose() + pieChart?.dispose() }) From 3affabc7e76c3f5d592ab494f0ff2987aa7ff83a Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Wed, 13 May 2026 10:05:59 +0800 Subject: [PATCH 04/12] =?UTF-8?q?feat(hfnf):=20=E7=B3=BB=E7=BB=9F=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E5=8C=BA=E5=9F=9F=E6=96=B0=E5=A2=9E=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=A0=87=E5=87=86=E9=A1=B5=E9=9D=A2=E8=B7=B3=E8=BD=AC=E9=93=BE?= =?UTF-8?q?=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- src/views/fac_cal/hfnf_index.vue | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/views/fac_cal/hfnf_index.vue b/src/views/fac_cal/hfnf_index.vue index fdb4b5e4..70c3417a 100644 --- a/src/views/fac_cal/hfnf_index.vue +++ b/src/views/fac_cal/hfnf_index.vue @@ -162,6 +162,15 @@ 进入测点数据明细 →
+
+
+ +
+
+ 数据标准 + 查看数据标准模板 → +
+
@@ -223,6 +232,10 @@ const goDetail = () => { router.push('/hfnf_mplogx') } +const goStandard = () => { + router.push('/cement_data_template') +} + const initBarChart = () => { if (!barChartRef.value) return barChart = echarts.init(barChartRef.value) From 64060a6e2f97f1ba404c88145bd68c491ef6d4df Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Fri, 15 May 2026 13:37:34 +0800 Subject: [PATCH 05/12] =?UTF-8?q?fix(hrm):=20=E8=A1=A5=E5=85=A8=E7=A6=BB?= =?UTF-8?q?=E8=81=8C=E7=94=B3=E8=AF=B7=E4=BA=A4=E6=8E=A5=E6=97=A5=E6=9C=9F?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复发起离职审批时报"请填写办理离职的交接日期"的问题: - 表单缺少 ticket_data 状态对象,导致工单流转时 handle_date 始终为空 - 审批阶段新增交接日期日期选择器,绑定到 ticket_data.handle_date - 查看详情时从后端响应回填 handle_date 实现回显 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/views/hrm/resignation_form.vue | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/views/hrm/resignation_form.vue b/src/views/hrm/resignation_form.vue index 274c5b40..c86e4af5 100644 --- a/src/views/hrm/resignation_form.vue +++ b/src/views/hrm/resignation_form.vue @@ -34,6 +34,15 @@ :readonly="localMode === 'show'" > + + + Date: Fri, 15 May 2026 15:08:27 +0800 Subject: [PATCH 06/12] =?UTF-8?q?feat:=20=E6=A0=87=E7=AD=BE=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E8=A1=A8=E5=8D=95=E5=A2=9E=E5=8A=A0=E6=89=93=E7=A0=81?= =?UTF-8?q?=E5=99=A8=E7=94=A8=E6=88=B7=E5=8C=BA=E9=85=8D=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增打码器用户区输入框, 对应后端 LabelTemplate.coder_field, 默认 1。 喷码机一条信息内插入多个不同码型的用户区时, 切码型即切模板。 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/views/sys/labeltemplate.vue | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/views/sys/labeltemplate.vue b/src/views/sys/labeltemplate.vue index 45f9d027..c9aa249b 100644 --- a/src/views/sys/labeltemplate.vue +++ b/src/views/sys/labeltemplate.vue @@ -53,6 +53,9 @@ + + + @@ -70,6 +73,7 @@ commands: "", coder_ip: "", coder_port: 3100, + coder_field: "1", }; export default { name: 'labeltemplate', @@ -154,6 +158,7 @@ this.addForm.commands=row.commands.join("\n"); this.addForm.coder_ip=row.coder_ip; this.addForm.coder_port=row.coder_port; + this.addForm.coder_field=row.coder_field || "1"; this.limitedVisible = true; }, From cacb54851715dd7e2e34c67655e3ffc58d90b649 Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Fri, 15 May 2026 17:03:06 +0800 Subject: [PATCH 07/12] =?UTF-8?q?fix(hrm):=20=E4=BA=BA=E5=91=98=E4=BA=A4?= =?UTF-8?q?=E6=8E=A5=E8=AF=A6=E6=83=85=E6=8A=BD=E5=B1=89=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E4=B8=8D=E5=9B=9E=E6=98=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit el-drawer 早期渲染插槽时 t_id 仍为 null,mounted() 走到 else 分支把 localMode 设成 add,后续 prop 变化 getTid 不再触发。 改用 watch t_id (immediate:true),prop 何时到位都能拉数据。 同时给 system.post.list 单独加 try/catch 并对 state_ 做空安全 访问,避免内层异常吃掉主数据赋值。 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/views/hrm/empjoin_form.vue | 41 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/views/hrm/empjoin_form.vue b/src/views/hrm/empjoin_form.vue index 9df17526..3ac84a7f 100644 --- a/src/views/hrm/empjoin_form.vue +++ b/src/views/hrm/empjoin_form.vue @@ -188,15 +188,22 @@ export default { }) }, deep: true, + }, + t_id: { + handler(val) { + this.localMode = this.mode; + if (val) { + this.getTid(); + } else { + this.formData = { person: [] }; + this.localMode = "add"; + } + }, + immediate: true, } }, mounted() { this.getGroup(); - if (this.t_id) { - this.getTid(); - } else { - this.localMode = "add"; - } }, methods: { async getTid() { @@ -204,18 +211,22 @@ export default { let res = await this.$API.hrm.empjoin.item.req(this.t_id); // 获取岗位列表,填充 post_name if (res.person && res.person.length > 0) { - const postRes = await this.$API.system.post.list.req({ page: 0 }); - const postList = Array.isArray(postRes) ? postRes : (postRes.results || postRes.data || []); - const postMap = {}; - postList.forEach(p => { postMap[p.id] = p.name; }); - res.person.forEach(p => { - if (p.post && !p.post_name) { - p.post_name = postMap[p.post] || ''; - } - }); + try { + const postRes = await this.$API.system.post.list.req({ page: 0 }); + const postList = Array.isArray(postRes) ? postRes : (postRes.results || postRes.data || []); + const postMap = {}; + postList.forEach(p => { postMap[p.id] = p.name; }); + res.person.forEach(p => { + if (p.post && !p.post_name) { + p.post_name = postMap[p.post] || ''; + } + }); + } catch (postErr) { + console.error('获取岗位列表失败:', postErr); + } } this.formData = res; - if (res.ticket_ && res.ticket_.state_.type == 1 && res.create_by == this.$TOOL.data.get("USER_INFO").id) { + if (res.ticket_ && res.ticket_.state_ && res.ticket_.state_.type == 1 && res.create_by == this.$TOOL.data.get("USER_INFO").id) { this.localMode = "edit"; } } catch (error) { From a9c3903864082979d6a815d94c5f1002aab04a04 Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Fri, 15 May 2026 17:03:16 +0800 Subject: [PATCH 08/12] =?UTF-8?q?feat(wf):=20=E4=BB=85=E9=83=A8=E9=97=A8?= =?UTF-8?q?=E8=B4=9F=E8=B4=A3=E4=BA=BA=E5=B2=97=E4=BD=8D=E5=8F=AF=E5=8F=91?= =?UTF-8?q?=E8=B5=B7=E8=AF=B7=E5=81=87=E5=AE=A1=E6=89=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按岗位筛选发起流程入口:调 system.userPost.list 取当前用户全部 岗位,命中"部门负责人"才放行 wf_leave。支持一个用户挂多个岗位。 后续要按岗位限流其他工单只需在 restrictedKeys 增加 key。 注意:仅前端隐藏入口,未做后端校验。 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/views/wf/myticket.vue | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/views/wf/myticket.vue b/src/views/wf/myticket.vue index c6873ab2..2e915692 100644 --- a/src/views/wf/myticket.vue +++ b/src/views/wf/myticket.vue @@ -218,12 +218,24 @@ export default { this.getWfOptions(); }, methods: { - getWfOptions() { + async getWfOptions() { let permissions = this.$TOOL.data.get("PERMISSIONS"); + let userInfo = this.$TOOL.data.get("USER_INFO"); + let isDeptHead = false; + try { + const userPosts = await this.$API.system.userPost.list.req({ user: userInfo.id, page: 0 }); + isDeptHead = (userPosts || []).some(up => up.post_ && up.post_.name === "部门负责人"); + } catch (e) { + console.error("获取用户岗位失败:", e); + } + const restrictedKeys = { wf_leave: isDeptHead }; const groups = {}; this.$API.wf.workflow.list.req({ page: 0 }).then((res) => { res.forEach((item) => { if(item.key && permissions.includes(item.key)) { + if (item.key in restrictedKeys && !restrictedKeys[item.key]) { + return; + } let cate = item.cate; if (!cate){cate="未分组"} if (!groups[cate]) { From 119fa9cb9475853374c5ae379ad5f9f67e0166ac Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Fri, 15 May 2026 17:03:30 +0800 Subject: [PATCH 09/12] =?UTF-8?q?fix(wf):=20=E5=B7=A5=E5=8D=95=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E6=8C=89=E9=92=AE=E5=81=B6=E5=B0=94=E4=B8=8D=E6=B8=B2?= =?UTF-8?q?=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ticketd_b 原先用 setTimeout 1s 后调 init(),挂载瞬间 props.ticket_ 还是 null,1 秒等待无法保证父表单 getTid 已完成且 props 已传到。 init 读到的 props.ticket_ 仍为 falsy 时会错误地走 workflow_key 分支调 init_key,把 transitions 初始化成新建工单的初始 transition, 导致审批人看不到"同意"等操作按钮。 改用 watch props.ticket_ / props.workflow_key 触发 init,并加 lastInitTicketId 去重避免重复调用。 复现:cuishuai 登录 → /ofm/publicity → 点详情 → 看不到"同意"按钮。 影响范围:所有使用 ticketd_b 的审批表单(请假/合同/宣传/维修等)。 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/views/wf/ticketd_b.vue | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/views/wf/ticketd_b.vue b/src/views/wf/ticketd_b.vue index 0078a9de..54f3eaed 100644 --- a/src/views/wf/ticketd_b.vue +++ b/src/views/wf/ticketd_b.vue @@ -34,18 +34,27 @@ const props = defineProps({ const workflow = ref(null); const transitions = ref([]); -onMounted(async () => { - setTimeout(()=>{init()}, 1000) - // watch( - // () => props.ticket_, - // async (newVal) => { - // if (newVal && Object.keys(newVal).length > 0) { - // init(); - // } - // }, - // { deep: true } - // ) -}) +let lastInitTicketId = null; +const tryInit = () => { + // 优先用 ticket_ 分支:等到 ticket_.id 出现再调 + if (props.ticket_ && props.ticket_.id) { + if (lastInitTicketId !== props.ticket_.id) { + lastInitTicketId = props.ticket_.id; + init(); + } + return; + } + // 没有 ticket_,退化到 workflow_key 分支(创建工单场景) + if (props.workflow_key) { + if (lastInitTicketId !== '__wf_key__:' + props.workflow_key) { + lastInitTicketId = '__wf_key__:' + props.workflow_key; + init(); + } + } +}; +onMounted(() => { tryInit(); }); +watch(() => props.ticket_, () => { tryInit(); }, { deep: true }); +watch(() => props.workflow_key, () => { tryInit(); }); const ticketId = ref(null); const actionShow = ref(false); From 11216e255463e038d6bca97310444d00335acc8e Mon Sep 17 00:00:00 2001 From: shijing Date: Fri, 15 May 2026 17:06:12 +0800 Subject: [PATCH 10/12] =?UTF-8?q?fix:=E6=9D=A5=E6=96=99=E6=9C=AA=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E5=90=88=E6=89=B9=E6=97=B6=E4=B9=9F=E5=8F=AF=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E6=B8=85=E9=99=A4=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/wpm_gx/inm.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/views/wpm_gx/inm.vue b/src/views/wpm_gx/inm.vue index 6aa4ef78..30ceb469 100644 --- a/src/views/wpm_gx/inm.vue +++ b/src/views/wpm_gx/inm.vue @@ -340,6 +340,7 @@ export default { let obj = {}; obj.wm = item.id; obj.batch = item.batch; + obj.state = item.state; obj.defect = item.defect; obj.material = item.material; obj.count_canhandover = item.count_canhandover; From 9e8046f9283ef6384803c5869588ab33303c4d03 Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Fri, 15 May 2026 17:08:09 +0800 Subject: [PATCH 11/12] =?UTF-8?q?feat:=E4=BF=AE=E6=94=B9=E5=85=89=E8=8A=AF?= =?UTF-8?q?bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/model/hfnf.js | 4 ++-- src/components/scTable/index.vue | 4 ++-- src/views/fac_cal/hfnf_index.vue | 8 +++++++- src/views/hrm/empcontract.vue | 4 +++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/api/model/hfnf.js b/src/api/model/hfnf.js index dab1212d..1e12772b 100644 --- a/src/api/model/hfnf.js +++ b/src/api/model/hfnf.js @@ -6,8 +6,8 @@ export default { name: "列表", req: async function(data){ return await http.post( - // `${config.HOST_URL}/hfnf_api/mplogx/`, - "http://10.0.11.52:5800/mplogx/", + `${config.HOST_URL}/hfnf_api/mplogx/`, + // "http://10.0.11.52:5800/mplogx/", data ); } diff --git a/src/components/scTable/index.vue b/src/components/scTable/index.vue index 74b2bb79..7056b838 100644 --- a/src/components/scTable/index.vue +++ b/src/components/scTable/index.vue @@ -10,9 +10,9 @@