feat: 优化储存卡能量格组件EnergyBar(更紧凑、可调尺寸、充能特效);修复样式命名冲突;微调色带进度条底色与不换行显示;清理调试信息

This commit is contained in:
24kycj
2025-09-15 21:47:42 +08:00
parent 859a8a985e
commit 2e1a1864aa
8 changed files with 2636 additions and 2296 deletions
+1 -1
View File
@@ -74,7 +74,7 @@ function startRenderer () {
} }
) )
server.listen(9080) server.listen(9081)
}) })
} }
+1 -1
View File
@@ -32,7 +32,7 @@ if (process.env.NODE_ENV !== "development") {
let mainWindow; let mainWindow;
const winURL = const winURL =
process.env.NODE_ENV === "development" process.env.NODE_ENV === "development"
? `http://localhost:9080` ? `http://localhost:9081`
: `file://${__dirname}/index.html`; : `file://${__dirname}/index.html`;
function createWindow() { function createWindow() {
+1 -1
View File
@@ -41,7 +41,7 @@ if (process.env.NODE_ENV !== "development") {
let mainWindow; let mainWindow;
const winURL = const winURL =
process.env.NODE_ENV === "development" process.env.NODE_ENV === "development"
? `http://localhost:9080` ? `http://localhost:9081`
: `file://${__dirname}/index.html`; : `file://${__dirname}/index.html`;
function createWindow() { function createWindow() {
+148
View File
@@ -0,0 +1,148 @@
<template>
<div class="energy-bar compact energy-dash" :title="tooltip">
<div class="energy-cells" :style="{ gap: gap + 'px' }">
<div
v-for="n in segments"
:key="n"
:class="cellClass(n)"
:style="{ width: cellWidth + 'px', height: cellHeight + 'px', borderRadius: borderRadius + 'px' }" />
</div>
</div>
</template>
<script>
export default {
name: 'EnergyBar',
props: {
// 百分比 0-100
percent: { type: Number, default: 0 },
// 段数 6 或 8
segments: { type: Number, default: 8 },
// 显示文本
showText: { type: Boolean, default: true },
// 自定义文本
text: { type: String, default: '' },
// 尺寸控制(像素)
cellWidth: { type: Number, default: 4 },
cellHeight: { type: Number, default: 10 },
gap: { type: Number, default: 1 },
borderRadius: { type: Number, default: 1 },
},
computed: {
litCells() {
const clamped = Math.max(0, Math.min(100, Math.round(this.percent || 0)))
// 一个能量格代表10(进1制向上取整)
const cells = Math.ceil(clamped / 10)
return Math.max(0, Math.min(this.segments, cells))
},
displayText() {
return this.text || `${Math.max(0, Math.min(100, Math.round(this.percent || 0)))}%`
},
tooltip() {
return this.displayText
},
tone() {
// 低电量红 / 中电量橙 / 高电量绿
const p = Math.max(0, Math.min(100, this.percent || 0))
if (p <= 20) return 'danger'
if (p <= 50) return 'warning'
return 'success'
},
chargingIndex() {
// 若不是整十,最后一格视为“充能中”
const p = Math.max(0, Math.min(100, this.percent || 0))
if (p % 10 === 0 || this.litCells === 0) return -1
return this.litCells
}
},
methods: {
cellClass(n) {
const lit = n <= this.litCells
// 仿数码表样式:前2格为红色,其余为绿色(只在被点亮时着色)
const zone = n <= 2 ? 'low' : 'high'
return [
'energy-cell',
lit ? (zone === 'low' ? 'is-red' : 'is-green') : 'is-off',
(this.chargingIndex === n && lit) ? 'is-charging' : ''
]
}
}
}
</script>
<style lang="less" scoped>
.energy-bar {
display: inline-flex;
}
.energy-dash {
/* 取消黑色底,采用透明背景以突出分隔与未点亮格 */
background: transparent;
padding: 1px 3px;
border-radius: 2px;
}
.compact .energy-cells {
display: flex;
align-items: center;
}
.energy-cell {
background: transparent;
box-sizing: border-box;
display: inline-block;
}
.energy-cell.is-red {
background: linear-gradient(180deg, #ff6b6b, #ff3f3f);
box-shadow: 0 0 2px rgba(255,58,58,.45);
position: relative;
overflow: hidden;
animation: pulse 2.8s ease-in-out infinite;
}
.energy-cell.is-green {
background: linear-gradient(180deg, #6dff55, #30cc42);
box-shadow: 0 0 2px rgba(103,255,77,.35);
position: relative;
overflow: hidden;
animation: pulse 2.8s ease-in-out infinite;
}
.energy-cell.is-off {
/* 提高对比度:更亮的灰底+更明显边框,便于在深色背景下辨识格数 */
background: #2f3643;
border: 1px solid #556179;
box-shadow: inset 0 1px 1px rgba(255,255,255,.06);
}
.energy-cell.is-charging {
position: relative;
overflow: hidden;
}
.energy-cell.is-charging::after {
content: '';
position: absolute;
left: -120%;
top: 0;
width: 120%;
height: 100%;
background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.28), rgba(255,255,255,0));
animation: sweep 2.4s linear infinite;
}
/* 所有点亮的格子也有较弱的扫光效果与更高亮度 */
.energy-cell.is-green::before,
.energy-cell.is-red::before {
content: '';
position: absolute;
left: -120%;
top: 0;
width: 120%;
height: 100%;
background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.18), rgba(255,255,255,0));
animation: sweep 3s linear infinite;
}
@keyframes pulse {
0% { filter: brightness(0.98); }
50% { filter: brightness(1.08); }
100% { filter: brightness(0.98); }
}
@keyframes sweep {
0% { left: -120%; }
100% { left: 120%; }
}
</style>
+1 -1
View File
@@ -1 +1 @@
{"files":["E:\\TortoiseGit License.txt"]} {"files":["\\\\NAS\\study\\research_reports\\2025\\数据资产价值释放之行业应用场景解析与合规框架——科学研究和技术服务业.pdf"]}
+98 -34
View File
@@ -223,7 +223,8 @@
:class="{ guide_body: beginStep && currentStep == 7 }"> :class="{ guide_body: beginStep && currentStep == 7 }">
<el-button <el-button
type="primary" type="primary"
@click="newWork"> @click="newWork"
:disabled="infoData.length == 0 && state == false">
{{ $t('index.newWork') }} {{ $t('index.newWork') }}
</el-button> </el-button>
</div> </div>
@@ -408,7 +409,7 @@
prop="status" prop="status"
:label="$t('main.tableState')" :label="$t('main.tableState')"
min-width="80"> min-width="80">
<template slot-scope="scope">{{ $t('main.tableOnline') }}</template> <template slot-scope="{}">{{ $t('main.tableOnline') }}</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="SerialNo" prop="SerialNo"
@@ -540,7 +541,9 @@
style="width: 100%" style="width: 100%"
size="mini" size="mini"
:empty-text="$t('index.nodata')" :empty-text="$t('index.nodata')"
row-class-name="rowclass"> row-class-name="rowclass"
:row-key="row => row.JobID || row.AssUuid"
:tree-props="{ children: 'children' }">
<el-table-column <el-table-column
label="#" label="#"
width="50"> width="50">
@@ -552,6 +555,10 @@
prop="jId" prop="jId"
:label="$t('index.wordID')" :label="$t('index.wordID')"
min-width="85"> min-width="85">
<template slot-scope="scope">
<span v-if="!scope.row.AssUuid">{{ scope.row.jId }}</span>
<span v-else>{{ (scope.row.ParentJobID || '') | shortJobId }}</span>
</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="DataSource" prop="DataSource"
@@ -562,20 +569,23 @@
:label="$t('index.wordSpace')" :label="$t('index.wordSpace')"
min-width="45"> min-width="45">
<template slot-scope="scope"> <template slot-scope="scope">
{{ getPrintName(scope.row.PrinterID, true) }} <span v-if="!scope.row.AssUuid">{{ getPrintName(scope.row.PrinterID, true) }}</span>
<span v-else>{{ getPrintName(scope.row.ParentPrinterID || scope.row.PrinterID, true) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
:label="$t('main.USBType')" :label="$t('main.USBType')"
min-width="55"> min-width="55">
<template slot-scope="scope"> <template slot-scope="scope">
{{ scope.row.PrinterType }} {{ !scope.row.AssUuid ? scope.row.PrinterType : (scope.row.ParentPrinterType || scope.row.PrinterType) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
min-width="60" min-width="60"
prop="TaskCapacity"
:label="$t('main.TaskCapacity')"> :label="$t('main.TaskCapacity')">
<template slot-scope="scope">
{{ !scope.row.AssUuid ? scope.row.TaskCapacity : (scope.row.ParentTaskCapacity || '') }}
</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
v-if="false" v-if="false"
@@ -583,9 +593,11 @@
:label="$t('main.taskFile')"> :label="$t('main.taskFile')">
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="CreateTime"
:label="$t('index.createTime')" :label="$t('index.createTime')"
min-width="75"> min-width="75">
<template slot-scope="scope">
{{ !scope.row.AssUuid ? scope.row.CreateTime : (scope.row.StartTime || '') }}
</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
v-if="false" v-if="false"
@@ -598,20 +610,25 @@
:filter-method="filterHandler"> :filter-method="filterHandler">
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="FinishTime"
:label="$t('index.finishedTime')" :label="$t('index.finishedTime')"
min-width="75"> min-width="75">
<template slot-scope="scope">
{{ !scope.row.AssUuid ? scope.row.FinishTime : (scope.row.FinishTime || '') }}
</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="JobCompletion"
min-width="40" min-width="40"
:label="$t('index.finishedNumber')"> :label="$t('index.finishedNumber')">
<template slot-scope="scope">
<span v-if="!scope.row.AssUuid">{{ scope.row.JobCompletion }}</span>
<span v-else>-</span>
</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
:label="$t('index.state')" :label="$t('index.state')"
prop="JobStatus"
width="135"> width="135">
<template slot-scope="scope"> <template slot-scope="scope">
<template v-if="!scope.row.AssUuid">
<el-dropdown <el-dropdown
trigger="click" trigger="click"
@command="(e) => handleTaskCommand(e, scope.row.JobID)" @command="(e) => handleTaskCommand(e, scope.row.JobID)"
@@ -638,9 +655,20 @@
:width="45" :width="45"
define-back-color="#ebeef5" define-back-color="#ebeef5"
:stroke-width="3" :stroke-width="3"
:percentage="parseFloat(scope.row.TaskPercentage.replace(`%`, ``))" :percentage="parseFloat((scope.row.TaskPercentage || '0').replace(`%`, ``))"
v-if="scope.row.JobStatus == `Copying`"></el-progress> v-if="scope.row.JobStatus == `Copying`"></el-progress>
</template> </template>
<template v-else>
{{ jobState(scope.row.TaskStatus) }}
<el-progress
:color="customColors"
:width="45"
define-back-color="#ebeef5"
:stroke-width="3"
:percentage="parseFloat((scope.row.TaskPercentage || '0').replace(`%`, ``))"
v-if="scope.row.TaskStatus == `Copying`"></el-progress>
</template>
</template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
@@ -823,6 +851,12 @@ export default {
warnCard, warnCard,
sFooter sFooter
}, },
filters: {
shortJobId(v) {
if (!v) return ''
return String(v).split('-')[0]
}
},
data() { data() {
return { return {
guideStep: null, guideStep: null,
@@ -1085,12 +1119,12 @@ export default {
this.getSystemInfo() this.getSystemInfo()
this.selectLan = localStorage.getItem('lang') this.selectLan = localStorage.getItem('lang')
this.isAdmin = localStorage.getItem('loginrole') == 'administrator' this.isAdmin = localStorage.getItem('loginrole') == 'administrator'
// const tempTimer = setInterval(() => { const tempTimer = setInterval(() => {
// if (JSON.stringify(this.ribbonList) != '{}') { if (JSON.stringify(this.ribbonList) != '{}') {
// this.getData(1) //首次触发需要先获取到Ribbon数据 this.getData(1) //首次触发需要先获取到Ribbon数据
// clearInterval(tempTimer) clearInterval(tempTimer)
// } }
// }, 200) }, 200)
ipcRenderer.on('open-program-callback', (event, data) => { ipcRenderer.on('open-program-callback', (event, data) => {
console.log(data) console.log(data)
this.openFile(data) this.openFile(data)
@@ -1105,13 +1139,12 @@ export default {
ipcRenderer.send('get-root') ipcRenderer.send('get-root')
ipcRenderer.send('open-program') ipcRenderer.send('open-program')
this.guideStep = JSON.parse(localStorage.getItem('guideStep')) this.guideStep = JSON.parse(localStorage.getItem('guideStep'))
console.log(this.guideStep)
this.currentStep = localStorage.getItem('currentStep') this.currentStep = localStorage.getItem('currentStep')
if ((!localStorage.getItem('hideStep') || localStorage.getItem('hideStep') == 0)&&this.currentStep>-1) this.showStep = true if ((!localStorage.getItem('hideStep') || localStorage.getItem('hideStep') == 0)&&this.currentStep>-1) this.showStep = true
setTimeout(() => { setTimeout(() => {
this.doingWorkStatus = false this.doingWorkStatus = false
}, 10000) }, 10000)
// this.timer2 = setInterval(this.getPrintData, this.refreshTime2) this.timer2 = setInterval(this.getPrintData, this.refreshTime2)
}, },
beforeDestroy() { beforeDestroy() {
this.stopTimer() this.stopTimer()
@@ -1265,13 +1298,31 @@ export default {
this.state = true this.state = true
let tasks = [...this.tasks] let tasks = [...this.tasks]
this.tasks = [] this.tasks = []
for (let item of res.data.unfinishedTasks) { const normalize = (task) => {
item.jId = item.JobID.split('-')[0] //+ "..."; const jId = (task.JobID || '').split('-')[0]
this.tasks.push(item) const parentCommon = {
jId,
ParentJobID: task.JobID,
ParentPrinterID: task.PrinterID,
ParentPrinterType: task.PrinterType,
ParentTaskCapacity: task.TaskCapacity
} }
for (let item of res.data.finishedTasks) { const children = Array.isArray(task.AssTask) ? task.AssTask.map((child) => ({
item.jId = item.JobID.split('-')[0] //+ "..."; ...child,
this.tasks.push(item) ...parentCommon
})) : []
return {
...task,
jId,
children
}
}
for (let item of (res.data.unfinishedTasks || [])) {
this.tasks.push(normalize(item))
}
for (let item of (res.data.finishedTasks || [])) {
this.tasks.push(normalize(item))
} }
let total1 = 0 let total1 = 0
let total2 = 0 let total2 = 0
@@ -1681,6 +1732,19 @@ export default {
} }
this.isNew = true this.isNew = true
this.dialogVisible = true this.dialogVisible = true
// 新建任务时重置文件列表与网络认证状态,避免上一次残留导致卡顿
this.$nextTick(() => {
const workRef = this.$refs.work
if (workRef && workRef.$refs && workRef.$refs.files && workRef.$refs.files.reset) {
workRef.$refs.files.reset()
}
if (workRef) {
workRef.networkAuthVisible = false
workRef.networkAuthPaths = []
workRef.networkCredentials = {}
workRef.submitLoading = false
}
})
}, },
newNetWork() { newNetWork() {
//this.isNew = true; //this.isNew = true;
@@ -1869,15 +1933,15 @@ export default {
watch: { watch: {
hasDoingWork: { hasDoingWork: {
handler() { handler() {
// if (this.hasDoingWork) { if (this.hasDoingWork) {
// this.intervalTime = parseInt(this.refreshTime1) this.intervalTime = parseInt(this.refreshTime1)
// clearInterval(this.timer1) clearInterval(this.timer1)
// this.timer1 = setInterval(this.initData, this.intervalTime) this.timer1 = setInterval(this.initData, this.intervalTime)
// } else { } else {
// this.intervalTime = parseInt(this.refreshTime2) this.intervalTime = parseInt(this.refreshTime2)
// clearInterval(this.timer1) clearInterval(this.timer1)
// this.timer1 = setInterval(this.initData, this.intervalTime) this.timer1 = setInterval(this.initData, this.intervalTime)
// } }
}, },
immediate: true immediate: true
}, },
+106 -32
View File
@@ -223,8 +223,7 @@
:class="{ guide_body: beginStep && currentStep == 7 }"> :class="{ guide_body: beginStep && currentStep == 7 }">
<el-button <el-button
type="primary" type="primary"
@click="newWork" @click="newWork">
:disabled="infoData.length == 0 && state == false">
{{ $t('index.newWork') }} {{ $t('index.newWork') }}
</el-button> </el-button>
</div> </div>
@@ -427,16 +426,13 @@
min-width="100"> min-width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-progress <el-progress
class="ribbon-progress"
:color="customColors" :color="customColors"
:width="45" :width="60"
define-back-color="#ebeef5" define-back-color="#dfe4ed"
:format="() => scope.row.RibbonAmount" :format="() => String(scope.row.RibbonAmount || 0)"
:stroke-width="3" :stroke-width="3"
:percentage=" :percentage="safePercent(scope.row.RibbonAmount, getRibbonAmount(scope.row.ModeName, scope.row.RibbonType))"></el-progress>
scope.row.RibbonAmount == undefined || scope.row.RibbonAmount == '0'
? 0
: parseFloat(((scope.row.RibbonAmount / getRibbonAmount(scope.row.ModeName, scope.row.RibbonType)) * 100).toFixed(0))
"></el-progress>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@@ -474,17 +470,11 @@
:label="$t('main.tablePrinterRemaCapa')" :label="$t('main.tablePrinterRemaCapa')"
min-width="100"> min-width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-progress <EnergyBar
:color="customColors" :percent="safePercent((scope.row.PrinterRemaCapa > 0 ? scope.row.PrinterRemaCapa : 0), getPrinterRemaCapaAmount(scope.row.ModeName))"
:width="45" :segments="(scope.row.ModeName === 'TH80N' ? 6 : 8)"
define-back-color="#ebeef5" :showText="true"
:format="() => (scope.row.PrinterRemaCapa > 0 ? scope.row.PrinterRemaCapa : 0)" :text="String(scope.row.PrinterRemaCapa > 0 ? scope.row.PrinterRemaCapa : 0)" />
:stroke-width="3"
:percentage="
scope.row.PrinterRemaCapa == undefined || scope.row.PrinterRemaCapa == '0'
? 0
: parseFloat((((scope.row.PrinterRemaCapa > 0 ? scope.row.PrinterRemaCapa : 0) / getPrinterRemaCapaAmount(scope.row.ModeName)) * 100).toFixed(0))
"></el-progress>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -541,14 +531,14 @@
style="width: 100%" style="width: 100%"
size="mini" size="mini"
:empty-text="$t('index.nodata')" :empty-text="$t('index.nodata')"
row-class-name="rowclass" :row-class-name="rowClassName"
:row-key="row => row.JobID || row.AssUuid" :row-key="row => row.JobID || row.AssUuid"
:tree-props="{ children: 'children' }"> :tree-props="{ children: 'children' }">
<el-table-column <el-table-column
label="#" label="#"
width="50"> width="50">
<template slot-scope="scope"> <template slot-scope="scope">
{{ scope.$index + 1 }} <span v-if="!scope.row.AssUuid">{{ parentIndex(scope.row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@@ -557,13 +547,16 @@
min-width="85"> min-width="85">
<template slot-scope="scope"> <template slot-scope="scope">
<span v-if="!scope.row.AssUuid">{{ scope.row.jId }}</span> <span v-if="!scope.row.AssUuid">{{ scope.row.jId }}</span>
<span v-else>{{ (scope.row.ParentJobID || '') | shortJobId }}</span> <span v-else></span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="DataSource"
:label="$t('index.wordOrigin')" :label="$t('index.wordOrigin')"
min-width="50"> min-width="50">
<template slot-scope="scope">
<span v-if="!scope.row.AssUuid">{{ scope.row.DataSource }}</span>
<span v-else></span>
</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
:label="$t('index.wordSpace')" :label="$t('index.wordSpace')"
@@ -655,7 +648,7 @@
:width="45" :width="45"
define-back-color="#ebeef5" define-back-color="#ebeef5"
:stroke-width="3" :stroke-width="3"
:percentage="parseFloat((scope.row.TaskPercentage || '0').replace(`%`, ``))" :percentage="Math.max(0, Math.min(100, Number(String(scope.row.TaskPercentage || '0').replace('%','')) || 0))"
v-if="scope.row.JobStatus == `Copying`"></el-progress> v-if="scope.row.JobStatus == `Copying`"></el-progress>
</template> </template>
<template v-else> <template v-else>
@@ -665,7 +658,7 @@
:width="45" :width="45"
define-back-color="#ebeef5" define-back-color="#ebeef5"
:stroke-width="3" :stroke-width="3"
:percentage="parseFloat((scope.row.TaskPercentage || '0').replace(`%`, ``))" :percentage="Math.max(0, Math.min(100, Number(String(scope.row.TaskPercentage || '0').replace('%','')) || 0))"
v-if="scope.row.TaskStatus == `Copying`"></el-progress> v-if="scope.row.TaskStatus == `Copying`"></el-progress>
</template> </template>
</template> </template>
@@ -842,6 +835,7 @@ import sFooter from './footer.vue'
import warnCard from './warn-card.vue' import warnCard from './warn-card.vue'
import N80N from '../assets/80N.png' import N80N from '../assets/80N.png'
import N800N from '../assets/800N.png' import N800N from '../assets/800N.png'
import EnergyBar from './EnergyBar.vue'
export default { export default {
name: 'Main', name: 'Main',
@@ -849,7 +843,8 @@ export default {
work, work,
worknet, worknet,
warnCard, warnCard,
sFooter sFooter,
EnergyBar
}, },
filters: { filters: {
shortJobId(v) { shortJobId(v) {
@@ -1150,6 +1145,27 @@ export default {
this.stopTimer() this.stopTimer()
}, },
methods: { methods: {
rowClassName({ row }) {
// 子任务行更紧凑
return row.AssUuid ? 'ass-row' : ''
},
safePercent(value, total) {
const v = Number(value)
const t = Number(total)
if (!isFinite(v) || !isFinite(t) || t <= 0) return 0
const p = (v / t) * 100
if (!isFinite(p) || isNaN(p)) return 0
return Math.max(0, Math.min(100, Math.round(p)))
},
parentIndex(row) {
// 只对父任务计算序号:按 tasks 顶层数组索引 + 1
if (row && !row.AssUuid) {
const id = row.JobID
const idx = (this.tasks || []).findIndex(t => t.JobID === id)
return idx >= 0 ? idx + 1 : ''
}
return ''
},
initData() { initData() {
this.getData() this.getData()
this.getLogData() this.getLogData()
@@ -1305,7 +1321,8 @@ export default {
ParentJobID: task.JobID, ParentJobID: task.JobID,
ParentPrinterID: task.PrinterID, ParentPrinterID: task.PrinterID,
ParentPrinterType: task.PrinterType, ParentPrinterType: task.PrinterType,
ParentTaskCapacity: task.TaskCapacity ParentTaskCapacity: task.TaskCapacity,
ParentDataSource: task.DataSource
} }
const children = Array.isArray(task.AssTask) ? task.AssTask.map((child) => ({ const children = Array.isArray(task.AssTask) ? task.AssTask.map((child) => ({
...child, ...child,
@@ -1741,7 +1758,6 @@ export default {
if (workRef) { if (workRef) {
workRef.networkAuthVisible = false workRef.networkAuthVisible = false
workRef.networkAuthPaths = [] workRef.networkAuthPaths = []
workRef.networkCredentials = {}
workRef.submitLoading = false workRef.submitLoading = false
} }
}) })
@@ -1755,10 +1771,12 @@ export default {
return String.fromCharCode(65 + parseInt(n)) return String.fromCharCode(65 + parseInt(n))
}, },
getPrintName(id, onlyId) { getPrintName(id, onlyId) {
const safeId = (id && typeof id === 'string') ? id : ''
const tail = safeId.length >= 5 ? safeId.substr(-5) : safeId || '--'
if (onlyId === true) { if (onlyId === true) {
return id.substr(-5) return tail
} }
return this.$t('index.wordSpace') + id.substr(-5) return this.$t('index.wordSpace') + tail
}, },
getPrinterRemaCapaAmount(ModeName) { getPrinterRemaCapaAmount(ModeName) {
// console.log('PrinterRemaCapa', this.ribbonList[ModeName].PrinterRemaCapa) // console.log('PrinterRemaCapa', this.ribbonList[ModeName].PrinterRemaCapa)
@@ -2158,6 +2176,30 @@ a {
} }
} }
/* 子任务行紧凑显示 */
/deep/ .el-table__row.ass-row > td {
padding-top: 2px !important;
padding-bottom: 2px !important;
}
/deep/ .el-table__row.ass-row .cell {
line-height: 18px !important;
}
/* 去除树结构行默认左侧过大缩进,让箭头与内容更紧凑 */
/deep/ .el-table__expand-icon {
margin-right: 2px;
}
/* 缩小树结构图标列宽与缩进 */
/deep/ .el-table__indent {
padding-left: 8px !important;
}
/deep/ .el-table__expand-icon > i {
font-size: 12px;
}
/* 进度条内数字不换行 */
/deep/ .ribbon-progress .el-progress-bar__innerText {
white-space: nowrap;
}
.user { .user {
font-size: 15px; font-size: 15px;
display: flex; display: flex;
@@ -2217,6 +2259,38 @@ a {
border-radius: 20px; border-radius: 20px;
} }
} }
/* 色带进度条样式优化 */
/deep/ .ribbon-progress .el-progress-bar__outer {
background: linear-gradient(180deg, #f3f6fa, #e5ebf5);
border-radius: 6px;
border: 1px solid #cfd6e3;
box-shadow: inset 0 1px 2px rgba(0,0,0,.08);
}
/deep/ .ribbon-progress .el-progress-bar__inner {
border-radius: 6px;
}
+.ribbon-wrap {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 2px 6px;
border-radius: 10px;
background: rgba(255,255,255,.35);
backdrop-filter: blur(3px);
}
+.ribbon-badge {
min-width: 30px;
height: 18px;
line-height: 18px;
padding: 0 8px;
border-radius: 9px;
background: linear-gradient(145deg, #1f2430, #0e1118);
color: #bfe3ff;
font-size: 12px;
text-align: center;
box-shadow: 0 2px 8px rgba(0,0,0,.15), inset 0 0 8px rgba(120,180,255,.25);
}
</style> </style>
<style> <style>
.rowclass { .rowclass {
+59 -5
View File
@@ -1209,6 +1209,10 @@ export default {
this.loadNetworkCredentials() this.loadNetworkCredentials()
this.getTemplates() this.getTemplates()
// 加载已保存的网络认证,支持二次新建直接使用
if (this.loadNetworkCredentials) {
this.loadNetworkCredentials()
}
}, },
updated() {}, updated() {},
methods: { methods: {
@@ -1244,14 +1248,50 @@ export default {
// 检查是否有网络路径需要认证 // 检查是否有网络路径需要认证
checkNetworkPaths() { checkNetworkPaths() {
if (this.$refs.files && this.$refs.files.hasNetworkPaths()) { if (!(this.$refs.files && this.$refs.files.hasNetworkPaths())) {
const networkPaths = this.$refs.files.getNetworkPaths() return false
if (networkPaths.length > 0) { }
this.networkAuthPaths = networkPaths const networkPaths = this.$refs.files.getNetworkPaths() || []
if (networkPaths.length === 0) return false
// 从本地存储的 credentials 中匹配已有主机
let stored = {}
try {
stored = JSON.parse(localStorage.getItem('networkCredentials') || '{}')
} catch (e) {
stored = {}
}
const missing = []
const prepared = []
for (const item of networkPaths) {
const host = item.hostName || this.getHostFromPath(item.path) || ''
if (host && stored[host] && stored[host].userName && stored[host].password) {
prepared.push({
host_name: host,
user_name: stored[host].userName,
password: stored[host].password,
})
} else {
missing.push({ ...item, hostName: host })
}
}
if (missing.length > 0) {
// 仅对缺失凭据的主机弹窗
this.networkAuthPaths = missing.map(m => ({
path: m.path,
hostName: m.hostName,
userName: '',
password: ''
}))
this.networkAuthVisible = true this.networkAuthVisible = true
// 先保存已准备好的,等用户补齐再一起提交
this.networkCredentials = prepared
return true return true
} }
}
// 全部已有凭据,直接使用
this.networkCredentials = prepared
return false return false
}, },
@@ -2426,6 +2466,20 @@ export default {
}, },
help() { help() {
ipcRenderer.send('open-help-file') ipcRenderer.send('open-help-file')
},
// 从路径提取主机名(兼容 \\host\path 与 //host/path
getHostFromPath(p) {
if (!p || typeof p !== 'string') return ''
if (p.indexOf('\\\\') === 0) {
const parts = p.slice(2).split('\\')
return parts[0] || ''
}
if (p.indexOf('//') === 0) {
const parts = p.slice(2).split('/')
return parts[0] || ''
}
const m = p.match(/^([^\\\/:]+)/)
return (m && m[1]) ? m[1] : ''
} }
}, },
computed: { computed: {