调整
This commit is contained in:
+28
-5
@@ -14,6 +14,14 @@ class ScreenRecorder {
|
||||
this.mainWindow = window;
|
||||
}
|
||||
|
||||
// 重置录制状态(用于前端初始化时清理可能的僵尸状态)
|
||||
resetRecording() {
|
||||
this.isRecording = false;
|
||||
this.recordedChunks = [];
|
||||
console.log('Recording state reset by renderer');
|
||||
return { success: true, message: 'State reset' };
|
||||
}
|
||||
|
||||
async startRecording() {
|
||||
if (this.isRecording) {
|
||||
return { success: false, message: '正在录制中' };
|
||||
@@ -45,7 +53,7 @@ class ScreenRecorder {
|
||||
}
|
||||
}
|
||||
|
||||
async stopRecording(videoData, taskId = '') {
|
||||
async stopRecording(videoData, taskId = '', customPath = null) {
|
||||
if (!this.isRecording) {
|
||||
return { success: false, message: '当前没有进行录制' };
|
||||
}
|
||||
@@ -53,11 +61,22 @@ class ScreenRecorder {
|
||||
try {
|
||||
this.isRecording = false;
|
||||
|
||||
// 确保videos目录存在 - 在应用根目录下
|
||||
// 获取应用根目录
|
||||
const appPath = process.env.NODE_ENV === 'development'
|
||||
? path.join(__dirname, '../../')
|
||||
: path.dirname(app.getPath('exe'));
|
||||
const videosDir = path.join(appPath, 'videos');
|
||||
|
||||
let videosDir;
|
||||
if (customPath) {
|
||||
// 如果是绝对路径直接使用,否则拼接应用根目录
|
||||
videosDir = path.isAbsolute(customPath)
|
||||
? customPath
|
||||
: path.join(appPath, customPath);
|
||||
} else {
|
||||
// 默认目录:应用根目录/videos
|
||||
videosDir = path.join(appPath, 'videos');
|
||||
}
|
||||
|
||||
if (!fs.existsSync(videosDir)) {
|
||||
fs.mkdirSync(videosDir, { recursive: true });
|
||||
}
|
||||
@@ -113,14 +132,18 @@ ipcMain.handle('start-recording', async () => {
|
||||
return await recorder.startRecording();
|
||||
});
|
||||
|
||||
ipcMain.handle('stop-recording', async (event, videoData, taskId) => {
|
||||
return await recorder.stopRecording(videoData, taskId);
|
||||
ipcMain.handle('stop-recording', async (event, videoData, taskId, customPath) => {
|
||||
return await recorder.stopRecording(videoData, taskId, customPath);
|
||||
});
|
||||
|
||||
ipcMain.handle('get-videos-path', () => {
|
||||
return recorder.getVideosPath();
|
||||
});
|
||||
|
||||
ipcMain.handle('reset-recording', async () => {
|
||||
return recorder.resetRecording();
|
||||
});
|
||||
|
||||
// 使用全局变量方式,避免webpack模块转换问题
|
||||
global.ScreenRecorderInstance = recorder;
|
||||
global.setMainWindow = (window) => recorder.setMainWindow(window);
|
||||
|
||||
@@ -125,11 +125,11 @@ export default {
|
||||
methods: {
|
||||
// 获取配置
|
||||
getConfig() {
|
||||
this.$axios.get('/admin/get_config')
|
||||
this.$axios.get('/web/get_config')
|
||||
.then(res => {
|
||||
if (res && res.data) {
|
||||
// 合并数据,确保所有字段都存在
|
||||
this.iniData = { ...this.iniData, ...res.data };
|
||||
this.iniData = { ...this.iniData, ...res.data.data };
|
||||
} else {
|
||||
this.$message.error(this.$t("dispose.errorRead"));
|
||||
}
|
||||
@@ -139,23 +139,23 @@ export default {
|
||||
this.$message.error(this.$t("dispose.errorRead"));
|
||||
});
|
||||
},
|
||||
// 保存配置
|
||||
save() {
|
||||
this.$axios.post('/admin/get_config', this.iniData)
|
||||
.then(res => {
|
||||
if (res && (res.data === "success" || res.status === 200)) {
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: this.$t("dispose.successReserve"),
|
||||
});
|
||||
} else {
|
||||
// 某些接口可能返回 { ret: 0 } 或其他形式,视具体情况而定
|
||||
// 这里假设200 OK即为成功,或者根据res.data判断
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: this.$t("dispose.successReserve"),
|
||||
});
|
||||
// 构造 query string
|
||||
let params = [];
|
||||
for (let key in this.iniData) {
|
||||
if (this.iniData.hasOwnProperty(key)) {
|
||||
// 使用 encodeURIComponent 确保特殊字符正确传输
|
||||
params.push(`${key}=${encodeURIComponent(this.iniData[key])}`);
|
||||
}
|
||||
}
|
||||
const queryString = params.join('&');
|
||||
|
||||
this.$axios.post(`/web/update_config?${queryString}`)
|
||||
.then(res => {
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: this.$t("dispose.successReserve"),
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<template v-if="!statusOnly">
|
||||
<el-tooltip :content="isRecording ? $t('recorder.stopRecording') : $t('recorder.startRecording')" placement="top">
|
||||
<el-button size="medium" :type="isRecording ? 'danger' : 'primary'"
|
||||
:icon="isRecording ? 'el-icon-video-pause' : 'el-icon-video-camera'" circle @click="toggleRecording"
|
||||
:icon="isRecording ? 'el-icon-switch-button' : 'el-icon-video-camera'" circle @click="toggleRecording"
|
||||
:loading="loading" class="record-btn">
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
@@ -43,7 +43,9 @@ export default {
|
||||
timer: null,
|
||||
stream: null,
|
||||
currentTaskId: '', // 录屏开始时的任务ID
|
||||
autoSave: true // 是否在停止时保存
|
||||
autoSave: true, // 是否在停止时保存
|
||||
videoPath: '', // 录制视频的绝对路径
|
||||
customSavePath: '' // 存储启动时传入的保存路径
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
@@ -86,6 +88,7 @@ export default {
|
||||
|
||||
this.stream = stream;
|
||||
this.recordedChunks = [];
|
||||
this.customSavePath = options.savePath || ''; // 保存自定义路径
|
||||
|
||||
// 创建MediaRecorder
|
||||
this.mediaRecorder = new MediaRecorder(stream, {
|
||||
@@ -100,7 +103,7 @@ export default {
|
||||
|
||||
this.mediaRecorder.onstop = async () => {
|
||||
if (this.autoSave) {
|
||||
await this.saveRecording(options.savePath);
|
||||
await this.saveRecording(this.customSavePath); // 使用保存的路径
|
||||
}
|
||||
this.recordedChunks = [];
|
||||
};
|
||||
@@ -130,7 +133,22 @@ export default {
|
||||
|
||||
try {
|
||||
if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
|
||||
// 创建 Promise 等待 onstop 回调完成
|
||||
await new Promise((resolve) => {
|
||||
// 保存原有的 onstop 处理器
|
||||
const originalOnStop = this.mediaRecorder.onstop;
|
||||
|
||||
// 包装 onstop,在原处理器完成后 resolve
|
||||
this.mediaRecorder.onstop = async (event) => {
|
||||
if (originalOnStop) {
|
||||
await originalOnStop.call(this, event);
|
||||
}
|
||||
resolve();
|
||||
};
|
||||
|
||||
// 触发 stop 事件
|
||||
this.mediaRecorder.stop();
|
||||
});
|
||||
}
|
||||
|
||||
// 停止所有轨道
|
||||
@@ -161,6 +179,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
// 将录制的数据块合并为Blob
|
||||
const blob = new Blob(this.recordedChunks, {
|
||||
@@ -170,24 +189,37 @@ export default {
|
||||
// 转换为base64
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = async () => {
|
||||
if (this._isDestroyed) return;
|
||||
try {
|
||||
const base64data = reader.result;
|
||||
|
||||
// 发送到主进程保存,传递任务ID和可选路径
|
||||
const result = await ipcRenderer.invoke('stop-recording', base64data, this.currentTaskId, customPath);
|
||||
|
||||
if (this._isDestroyed) return;
|
||||
|
||||
if (result.success) {
|
||||
this.$message.success(this.$t('recorder.savedSuccess') + `: ${result.fileName}`);
|
||||
this.videoPath = result.filePath; // 保存视频绝对路径供外部使用
|
||||
this.$emit('recording-saved', result);
|
||||
resolve(result);
|
||||
} else {
|
||||
this.$message.error(result.message);
|
||||
reject(new Error(result.message));
|
||||
}
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
};
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
|
||||
} catch (error) {
|
||||
console.error('保存录制失败:', error);
|
||||
this.$message.error(this.$t('recorder.saveFailed'));
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
startTimer() {
|
||||
|
||||
@@ -17,13 +17,6 @@
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer grand-footer">
|
||||
<div class="footer-buttons">
|
||||
<el-button @click="handleClose" size="medium" icon="el-icon-close">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="handleSave" size="medium" icon="el-icon-check">{{ $t('common.confirm')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -81,8 +74,8 @@ export default {
|
||||
},
|
||||
handleSave() {
|
||||
// 验证加密狗计数
|
||||
if (this.form.is_dongle_count) {
|
||||
if (!this.form.dongle_count || this.form.dongle_count <= 0 || !Number.isInteger(this.form.dongle_count)) {
|
||||
if (this.form.enable_dongle_counter) {
|
||||
if (!this.form.install_dongle_count || this.form.install_dongle_count < 0 || !Number.isInteger(this.form.install_dongle_count)) {
|
||||
this.$message.warning(this.$t('work.dongleCountRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,39 +45,63 @@
|
||||
<div class="sub-title">
|
||||
<i class="el-icon-edit-outline"></i>
|
||||
<span>{{ $t('work.metadataEdit') }}</span>
|
||||
<span class="field-count" v-if="tableData && tableData.length > 0">({{ tableData.length }})</span>
|
||||
</div>
|
||||
<el-table v-if="tableData && tableData.length > 0" :data="tableData" class="metadata-table flex-grow-table"
|
||||
:empty-text="$t('work.nodata')" :show-header="false">
|
||||
|
||||
<el-table-column prop="name" min-width="110"></el-table-column>
|
||||
<el-table-column min-width="240">
|
||||
<template slot-scope="scope">
|
||||
<div v-if="scope.row.type == 1">
|
||||
<input type="file" title="" accept="image/*" :ref="scope.row.origin_name"
|
||||
:data-name="scope.row.origin_name"
|
||||
@change="(e) => $emit('image-change', scope.row.origin_name, e.target.files[0])" />
|
||||
<!-- 卡片式布局替代表格 -->
|
||||
<div v-if="tableData && tableData.length > 0" class="metadata-fields-list">
|
||||
<div v-for="(item, index) in tableData" :key="index" class="field-item"
|
||||
:class="{ 'field-disabled': csvIsExist && (item.type == 3 || item.type == 4 || item.type == 5) }">
|
||||
|
||||
<!-- 左侧:字段名称区域 -->
|
||||
<div class="field-label-area">
|
||||
<div class="field-info">
|
||||
<div class="field-name-row">
|
||||
<span class="field-name" :title="item.name">{{ item.name }}</span>
|
||||
<span v-if="item.sideLabel" class="side-badge"
|
||||
:class="{ 'side-front': item.sideLabel.includes('正'), 'side-back': item.sideLabel.includes('背') }">
|
||||
{{ item.sideLabel.replace('[', '').replace(']', '') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else-if="scope.row.type == 3 || scope.row.type == 4 || scope.row.type == 5">
|
||||
<el-input v-model="form[scope.row.origin_name]" clearable size="mini"
|
||||
:disabled="csvIsExist" />
|
||||
</div>
|
||||
<div v-else>{{ scope.row.origin_name }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="90">
|
||||
<template slot-scope="scope">
|
||||
<div v-if="scope.row.type == 3 || scope.row.type == 4 || scope.row.type == 5">
|
||||
<el-button size="mini" icon="el-icon-upload2" @click="$emit('open-csv')">
|
||||
{{ file_name ? file_name : $t('work.binfile') }}
|
||||
</div>
|
||||
|
||||
<!-- 右侧:输入区域 -->
|
||||
<div class="field-input-area">
|
||||
<!-- 图片类型 -->
|
||||
<div v-if="item.type == 1" class="image-upload-wrapper">
|
||||
<label :for="'upload-' + item.origin_name" class="upload-label">
|
||||
<i class="el-icon-picture-outline"></i>
|
||||
<span>{{ $t('work.selectImage') }}</span>
|
||||
</label>
|
||||
<input :id="'upload-' + item.origin_name" type="file" accept="image/*"
|
||||
:ref="item.origin_name" :data-name="item.origin_name" class="hidden-file-input"
|
||||
@change="(e) => $emit('image-change', item.origin_name, e.target.files[0])" />
|
||||
</div>
|
||||
|
||||
<!-- 文本/条码类型 -->
|
||||
<div v-else-if="item.type == 3 || item.type == 4 || item.type == 5" class="text-input-wrapper">
|
||||
<el-input v-model="form[item.origin_name]" :placeholder="$t('work.pleaseInput')" clearable
|
||||
size="small" :disabled="csvIsExist" class="modern-input" />
|
||||
<el-button size="small" icon="el-icon-upload2" @click="$emit('open-csv')"
|
||||
class="csv-import-btn" :title="$t('work.binfile')">
|
||||
<span class="btn-text">{{ file_name || $t('work.binfile') }}</span>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 其他类型 -->
|
||||
<div v-else class="field-value-display">
|
||||
{{ item.origin_name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态占位框 (当无数据时显示) -->
|
||||
<div v-else class="empty-placeholder-box">
|
||||
<span class="empty-text">{{ $t('work.nodata') }}</span>
|
||||
<div v-else class="empty-state-modern">
|
||||
<i class="el-icon-document"></i>
|
||||
<p class="empty-title">{{ $t('work.noTemplate') }}</p>
|
||||
<p class="empty-hint">{{ $t('work.selectTemplateHint') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -150,4 +174,235 @@ export default {
|
||||
.template-select {
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
/* ================== 现代化卡片式字段列表 ================== */
|
||||
.metadata-fields-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* 字段项卡片 */
|
||||
.field-item {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
padding: 14px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.field-item:hover {
|
||||
border-color: #cbd5e1;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.field-disabled {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 左侧:字段名称区域 */
|
||||
.field-label-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-width: 180px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.field-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.field-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
margin-bottom: 2px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.field-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.side-badge {
|
||||
font-size: 11px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.side-front {
|
||||
background-color: #e0f2fe;
|
||||
color: #0369a1;
|
||||
border: 1px solid #bae6fd;
|
||||
}
|
||||
|
||||
.side-back {
|
||||
background-color: #fce7f3;
|
||||
color: #be185d;
|
||||
border: 1px solid #fbcfe8;
|
||||
}
|
||||
|
||||
/* 右侧:输入区域 */
|
||||
.field-input-area {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 图片上传样式 */
|
||||
.image-upload-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.upload-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 7px 14px;
|
||||
background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: #4b5563;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.upload-label:hover {
|
||||
background: linear-gradient(135deg, #e5e7eb 0%, #d1d5db 100%);
|
||||
border-color: #9ca3af;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.upload-label i {
|
||||
font-size: 16px;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.hidden-file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 文本输入样式 */
|
||||
.text-input-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modern-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.csv-import-btn {
|
||||
border-radius: 8px;
|
||||
border-color: #d1d5db;
|
||||
background: #ffffff;
|
||||
transition: all 0.2s;
|
||||
max-width: 140px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.csv-import-btn:hover {
|
||||
background: #f9fafb;
|
||||
border-color: #9ca3af;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.csv-import-btn .btn-text {
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.field-value-display {
|
||||
padding: 7px 12px;
|
||||
background: #f9fafb;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
/* ================== 字段计数 ================== */
|
||||
.field-count {
|
||||
font-size: 12px;
|
||||
color: #9ca3af;
|
||||
font-weight: 600;
|
||||
margin-left: 4px;
|
||||
padding: 2px 8px;
|
||||
background: #f3f4f6;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
/* ================== 现代化空状态 ================== */
|
||||
.empty-state-modern {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 48px 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-state-modern i {
|
||||
font-size: 56px;
|
||||
color: #cbd5e1;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.empty-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
font-size: 13px;
|
||||
color: #94a3b8;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ================== 滚动条美化 ================== */
|
||||
.metadata-fields-list::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.metadata-fields-list::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.metadata-fields-list::-webkit-scrollbar-thumb:hover {
|
||||
background: #94a3b8;
|
||||
}
|
||||
|
||||
.metadata-fields-list::-webkit-scrollbar-track {
|
||||
background: #f1f5f9;
|
||||
border-radius: 3px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,17 +13,12 @@
|
||||
<!-- 右侧功能按钮 -->
|
||||
<div class="header-buttons">
|
||||
<!-- 录制组件 (绿色圆形) -->
|
||||
<div class="recorder-wrapper" v-if="isRecording || high_setting_form.is_print_logo">
|
||||
<div class="recorder-wrapper"
|
||||
v-if="isRecording || high_setting_form.record_screen || high_setting_form.print_record_logo">
|
||||
<screen-recorder ref="screenRecorder" :task-id="upload_disk" :status-only="true"
|
||||
@recording-started="onRecordingStarted" @recording-stopped="onRecordingStopped"
|
||||
@recording-saved="onRecordingSaved" />
|
||||
<el-tooltip content="打印" placement="top">
|
||||
<div v-if="high_setting_form.is_print_logo" class="print-logo-indicator">
|
||||
<img src="static/images/luzhi.png" @error="onLogoError" v-if="!logoError"
|
||||
class="logo-img" />
|
||||
<i v-else class="el-icon-printer"></i>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 高级设置按钮 (白色) -->
|
||||
@@ -168,6 +163,7 @@ export default {
|
||||
switch_cont: true,
|
||||
switch_tag: true,
|
||||
submitLoading: false,
|
||||
sysAuthCode: '', // 系统配置授权码
|
||||
|
||||
// 新手引导
|
||||
guideStep: null,
|
||||
@@ -191,25 +187,31 @@ export default {
|
||||
|
||||
// 高级设置表单
|
||||
high_setting_form: {
|
||||
// 基础配置
|
||||
priority: 0,
|
||||
fileSystem: 0,
|
||||
target_work: 0,
|
||||
color_type: 0,
|
||||
s1: false,
|
||||
s2: false,
|
||||
s3: false,
|
||||
formatFile: 0,
|
||||
|
||||
// 开关选项
|
||||
s1: false, // 生成MD5 HASH文件
|
||||
s2: false, // 打印MD5到HASH字段
|
||||
s3: false, // 失败打印标签
|
||||
s4: false,
|
||||
s5: false,
|
||||
|
||||
// 密码相关
|
||||
pass: '',
|
||||
repass: '',
|
||||
localfiles: false,
|
||||
formatFile: 0,
|
||||
Span_USBcard: false,
|
||||
hasAddFile: false,
|
||||
is_blend: false,
|
||||
is_record: false,
|
||||
record_path: '',
|
||||
is_print_logo: false,
|
||||
|
||||
// 功能开关
|
||||
localfiles: false, // 本地文件
|
||||
Span_USBcard: false, // 允许跨卡
|
||||
hasAddFile: false, // 预设内容拷贝
|
||||
is_blend: false, // 混合模式
|
||||
|
||||
// ISO/ZIP 生成
|
||||
is_generate_iso: false,
|
||||
iso_file_name: '',
|
||||
is_generate_zip: false,
|
||||
@@ -217,10 +219,17 @@ export default {
|
||||
is_zip_encrypt: false,
|
||||
zip_password: '',
|
||||
zip_repassword: '',
|
||||
copy_hash: false,
|
||||
is_dongle_count: false,
|
||||
dongle_count: 1,
|
||||
auth_code: ''
|
||||
copy_hash: false, // 拷贝HASH文件到存储卡
|
||||
|
||||
// 屏幕录制(重要:确保字段名称一致)
|
||||
record_screen: false, // 启用屏幕录制
|
||||
record_screen_path: '', // 录制路径
|
||||
print_record_logo: false, // 打印录制标识
|
||||
|
||||
// 硬件管控(重要:确保字段名称与提交逻辑一致)
|
||||
enable_dongle_counter: false, // 启用加密狗计数
|
||||
install_dongle_count: 0, // 安装次数(默认为0而不是1)
|
||||
auth_code: '' // 授权码
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -276,6 +285,8 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 重置后台录制状态,防止刷新后状态卡死
|
||||
ipcRenderer.invoke('reset-recording').catch(e => console.error('Reset recording failed:', e))
|
||||
extendStringPrototypes()
|
||||
this.upload_disk = genTaskUUID()
|
||||
},
|
||||
@@ -328,15 +339,15 @@ export default {
|
||||
this.high_setting_form = { ...this.high_setting_form, ...savedForm, ...defaults }
|
||||
|
||||
// 仅在路径为空时初始化默认路径(兼容三端)
|
||||
if (!this.high_setting_form.record_path) {
|
||||
this.high_setting_form.record_path = this.getDefaultRecordPath();
|
||||
if (!this.high_setting_form.record_screen_path) {
|
||||
this.high_setting_form.record_screen_path = this.getDefaultRecordPath();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to parse high settings')
|
||||
}
|
||||
} else {
|
||||
// 无缓存时初始化默认路径
|
||||
this.high_setting_form.record_path = this.getDefaultRecordPath();
|
||||
this.high_setting_form.record_screen_path = this.getDefaultRecordPath();
|
||||
}
|
||||
this.juanbiao_form = getNowFormatDate()
|
||||
this.print_flag = this.dice === 1 ? 2 : 1
|
||||
@@ -352,6 +363,17 @@ export default {
|
||||
this.guideStep[this.currentStep].show = true
|
||||
}, 200)
|
||||
}
|
||||
this.getSystemConfig(); // 获取系统配置
|
||||
},
|
||||
|
||||
getSystemConfig() {
|
||||
this.$axios.get('/web/get_config').then((res) => {
|
||||
if (res.data.code === 200 && res.data.data) {
|
||||
this.sysAuthCode = res.data.data.AuthorizationCode || '';
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('Failed to get system config', err);
|
||||
});
|
||||
},
|
||||
|
||||
// --- 高级设置与录制 ---
|
||||
@@ -391,8 +413,9 @@ export default {
|
||||
const recorder = this.$refs.screenRecorder;
|
||||
if (recorder) {
|
||||
if (recorder.isRecording) {
|
||||
recorder.stopRecording(true);
|
||||
this.$message.warning(this.$t('recorder.recording'));
|
||||
} else {
|
||||
this.highSettingVisible = false;
|
||||
recorder.startRecording({
|
||||
savePath: recordPath || this.getDefaultRecordPath()
|
||||
});
|
||||
@@ -440,7 +463,8 @@ export default {
|
||||
if ([1, 3, 4, 5].includes(item.type)) {
|
||||
const defaultVal = item.DefaultText !== undefined ? item.DefaultText : ''
|
||||
this.tableData.push({
|
||||
name: item.name + this.$t('work.front_tag'),
|
||||
name: item.name,
|
||||
sideLabel: this.$t('work.front_tag'),
|
||||
val: defaultVal,
|
||||
origin_name: item.name,
|
||||
type: item.type,
|
||||
@@ -457,7 +481,8 @@ export default {
|
||||
if ([1, 3, 4, 5].includes(item.type)) {
|
||||
const defaultVal = item.DefaultText !== undefined ? item.DefaultText : ''
|
||||
this.tableData.push({
|
||||
name: item.name + this.$t('work.back_tag'),
|
||||
name: item.name,
|
||||
sideLabel: this.$t('work.back_tag'),
|
||||
val: defaultVal,
|
||||
origin_name: item.name,
|
||||
type: item.type,
|
||||
@@ -991,14 +1016,12 @@ export default {
|
||||
'&zip_file_name=' + (that.high_setting_form.zip_file_name || '') +
|
||||
'&is_zip_encrypt=' + (String(that.high_setting_form.is_zip_encrypt) || 'false') +
|
||||
'&zip_password=' + (that.high_setting_form.zip_password || '') +
|
||||
'©_hash=' + (String(that.high_setting_form.copy_hash) || 'false') +
|
||||
'&enable_dongle_counter=' + (String(that.high_setting_form.enable_dongle_counter) || 'false') +
|
||||
'&auth_code=' + (that.high_setting_form.auth_code || '');
|
||||
'©_hash=' + (String(that.high_setting_form.copy_hash) || 'false');
|
||||
|
||||
data += '&is_blend=' + (String(that.high_setting_form.is_blend) || 'false');
|
||||
|
||||
// Log path logic
|
||||
if (that.high_setting_form.record_screen && that.$refs.screenRecorder && that.$refs.screenRecorder.videoPath) {
|
||||
if (that.$refs.screenRecorder && that.$refs.screenRecorder.videoPath) {
|
||||
data += '&record_path=' + that.$refs.screenRecorder.videoPath;
|
||||
} else {
|
||||
data += '&record_path=';
|
||||
@@ -1006,16 +1029,31 @@ export default {
|
||||
data += '&is_printer_record_logo=' + (String(that.high_setting_form.print_record_logo) || 'false');
|
||||
|
||||
if (that.high_setting_form.enable_dongle_counter) {
|
||||
data += '&donglel_install_count=' + (that.high_setting_form.install_dongle_count || 0);
|
||||
data += '&dongle_install_count=' + (that.high_setting_form.install_dongle_count || 1);
|
||||
} else {
|
||||
data += '&donglel_install_count=0';
|
||||
data += '&dongle_install_count=-1';
|
||||
}
|
||||
|
||||
// File Type Mapping
|
||||
const fileTypeMap = { 0: 1, 1: 2, 2: 3, 4: 4 };
|
||||
let apiFileType = fileTypeMap[that.file_form] || 1;
|
||||
data += '&file_type=' + apiFileType;
|
||||
console.log('提交参数预览:', data_param + data)
|
||||
// --- DEBUG: 输出提交数据 ---
|
||||
console.group('任务提交数据详情');
|
||||
|
||||
// 将查询字符串解析为对象,方便查看
|
||||
const queryString = data_param + data;
|
||||
const params = {};
|
||||
queryString.split('&').forEach(part => {
|
||||
if (part) {
|
||||
const [key, val] = part.split('=');
|
||||
params[key] = decodeURIComponent(val || '');
|
||||
}
|
||||
});
|
||||
console.log('提交参数对象 (JSON):', params);
|
||||
|
||||
console.log('高级设置表单:', JSON.parse(JSON.stringify(that.high_setting_form))); // 深拷贝打印
|
||||
console.groupEnd();
|
||||
|
||||
// Submit Flow
|
||||
if (this.isCopy) {
|
||||
this.submitLoading = true
|
||||
@@ -1047,9 +1085,8 @@ export default {
|
||||
|
||||
localUpload(pathName, data_param, data) {
|
||||
let file_path = []
|
||||
// 注意: 这里使用 getLists() 可能需要适配 legacy 的 filesList 结构
|
||||
// 如果 filesList[i].path 是正确路径,则无需更改
|
||||
const list = this.$refs.files.filesList // Prefer direct filesList if available like legacy
|
||||
// FileManagement 组件不直接暴露 filesList,需使用 getLists()
|
||||
const list = this.$refs.files.getLists()
|
||||
for (let i in list) {
|
||||
file_path.push(list[i].path)
|
||||
}
|
||||
|
||||
@@ -95,18 +95,15 @@
|
||||
</div>
|
||||
<div class="g-switch-item">
|
||||
<span class="g-label">{{ $t('work.installDongle') }}</span>
|
||||
<el-switch v-model="form.is_dongle_count"></el-switch>
|
||||
<el-switch v-model="form.enable_dongle_counter"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 计数器详细 -->
|
||||
<div v-if="form.is_dongle_count" class="mt-10 p-10"
|
||||
<div v-if="form.enable_dongle_counter" class="mt-10 p-10"
|
||||
style="background: #fdf6ec; border-radius: 6px; border: 1px solid #faecd8;">
|
||||
<el-form-item :label="$t('work.installCount')" label-width="140px" class="mb-5">
|
||||
<el-input-number v-model="form.dongle_count" :min="1" :step="1" :precision="0" size="mini" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('work.authCode')" label-width="140px" class="mb-0">
|
||||
<el-input v-model="form.auth_code" size="mini" :placeholder="$t('work.inputAuthCode')" />
|
||||
<el-form-item :label="$t('work.installCount')" label-width="140px" class="mb-0">
|
||||
<el-input-number v-model="form.install_dongle_count" :min="0" :step="1" :precision="0" size="mini" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
<el-col :span="12">
|
||||
<div class="hardware-box">
|
||||
<div class="mb-10">
|
||||
<el-checkbox v-model="form.is_dongle_count">
|
||||
<el-checkbox v-model="form.enable_dongle_counter">
|
||||
{{ $t('work.installDongle') }}
|
||||
</el-checkbox>
|
||||
</div>
|
||||
<transition name="el-zoom-in-top">
|
||||
<div v-if="form.is_dongle_count" class="ml-20">
|
||||
<div v-if="form.enable_dongle_counter" class="ml-20">
|
||||
<el-form-item :label="$t('work.installCount')" label-width="80px">
|
||||
<el-input-number size="small" v-model="form.dongle_count" :min="1" :max="999" />
|
||||
<el-input-number size="small" v-model="form.install_dongle_count" :min="0" :max="999" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
@@ -8,22 +8,21 @@
|
||||
<div class="grand-switch-grid mb-10">
|
||||
<div class="g-switch-item">
|
||||
<span class="g-label">{{ $t('work.enableScreenRecord') }}</span>
|
||||
<el-switch v-model="form.is_record"></el-switch>
|
||||
<el-switch v-model="form.record_screen"></el-switch>
|
||||
</div>
|
||||
<div class="g-switch-item" v-if="form.is_record">
|
||||
<div class="g-switch-item" v-if="form.record_screen">
|
||||
<div class="flex-align-center">
|
||||
<span class="g-label">{{ $t('work.printRecordLogo') }}</span>
|
||||
<i v-if="form.is_print_logo" class="el-icon-picture ml-5 logo-icon-active"
|
||||
title="luzhi.png"></i>
|
||||
|
||||
</div>
|
||||
<el-switch v-model="form.is_print_logo"></el-switch>
|
||||
<el-switch v-model="form.print_record_logo"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="form.is_record" class="path-box-container">
|
||||
<div v-if="form.record_screen" class="path-box-container">
|
||||
<div class="path-box">
|
||||
<el-form-item :label="$t('work.recordPath')" label-width="110px">
|
||||
<el-input v-model="form.record_path" :placeholder="$t('work.defaultPath')" size="small">
|
||||
<el-input v-model="form.record_screen_path" :placeholder="$t('work.defaultPath')" size="small">
|
||||
<el-button slot="append" icon="el-icon-folder-opened" @click="selectRecordPath"></el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
@@ -59,12 +58,12 @@ export default {
|
||||
properties: ['openDirectory']
|
||||
}).then(result => {
|
||||
if (!result.canceled && result.filePaths.length > 0) {
|
||||
this.$set(this.form, 'record_path', result.filePaths[0])
|
||||
this.$set(this.form, 'record_screen_path', result.filePaths[0])
|
||||
}
|
||||
})
|
||||
},
|
||||
testRecording() {
|
||||
this.$emit('test-recording', this.form.record_path);
|
||||
this.$emit('test-recording', this.form.record_screen_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-5
File diff suppressed because one or more lines are too long
+14
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user