录制和网络路径

This commit is contained in:
24kycj
2025-09-03 22:09:07 +08:00
parent b39e3356d3
commit 39d754d162
18 changed files with 3159 additions and 101 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>卡树自动拷贝打印系统 V3.0</title> <title>卡树自动拷贝打印系统 V3.1</title>
<% if (htmlWebpackPlugin.options.nodeModules) { %> <% if (htmlWebpackPlugin.options.nodeModules) { %>
<!-- Add `node_modules/` to global paths so `require` works properly in development --> <!-- Add `node_modules/` to global paths so `require` works properly in development -->
<script> <script>
+1 -1
View File
@@ -43,7 +43,7 @@ function createWindow() {
height: 800, height: 800,
useContentSize: true, useContentSize: true,
width: 1280, width: 1280,
title: "卡树自动拷贝打印系统 V3.0", title: "卡树自动拷贝打印系统 V3.1",
icon: "static/images/logo64.ico", // sets window icon icon: "static/images/logo64.ico", // sets window icon
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
+6 -2
View File
@@ -1,8 +1,11 @@
const { Menu, app, BrowserWindow } = require("electron"); const { Menu, app, BrowserWindow } = require("electron");
import "../renderer/store"; // Note: Store should be handled in renderer process, not main
// import "../renderer/store";
const fs = require('fs'); const fs = require('fs');
const child_process = require('child_process'); const child_process = require('child_process');
const path = require('path') const path = require('path')
// 导入录制器模块(设置全局变量)
require('./recorder');
// require("./fingerprint/win"); // require("./fingerprint/win");
let root = ""; let root = "";
if (process.env.NODE_ENV !== "development") { if (process.env.NODE_ENV !== "development") {
@@ -49,7 +52,7 @@ function createWindow() {
height: 800, height: 800,
useContentSize: true, useContentSize: true,
width: 1280, width: 1280,
title: "卡树自动拷贝打印系统 V3.0", title: "卡树自动拷贝打印系统 V3.1",
icon: "static/images/logo64.ico", // sets window icon icon: "static/images/logo64.ico", // sets window icon
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
@@ -65,6 +68,7 @@ function createWindow() {
//mainWindow.webContents.openDevTools({mode:'bottom'}); //mainWindow.webContents.openDevTools({mode:'bottom'});
require("@electron/remote/main").initialize(); require("@electron/remote/main").initialize();
require("@electron/remote/main").enable(mainWindow.webContents); require("@electron/remote/main").enable(mainWindow.webContents);
global.setMainWindow(mainWindow);
mainWindow.loadURL(winURL); mainWindow.loadURL(winURL);
mainWindow.on("closed", () => { mainWindow.on("closed", () => {
+117
View File
@@ -0,0 +1,117 @@
const { desktopCapturer, ipcMain, app } = require('electron');
const fs = require('fs');
const path = require('path');
class ScreenRecorder {
constructor() {
this.mediaRecorder = null;
this.recordedChunks = [];
this.isRecording = false;
this.mainWindow = null;
}
setMainWindow(window) {
this.mainWindow = window;
}
async startRecording() {
if (this.isRecording) {
return { success: false, message: '正在录制中' };
}
try {
// 获取屏幕源
const sources = await desktopCapturer.getSources({
types: ['screen'],
thumbnailSize: { width: 1920, height: 1080 }
});
if (sources.length === 0) {
return { success: false, message: '无法获取屏幕源' };
}
// 发送源ID到渲染进程
const sourceId = sources[0].id;
this.isRecording = true;
return {
success: true,
sourceId: sourceId,
message: '开始录制'
};
} catch (error) {
console.error('启动录制失败:', error);
return { success: false, message: error.message };
}
}
async stopRecording(videoData) {
if (!this.isRecording) {
return { success: false, message: '当前没有进行录制' };
}
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');
if (!fs.existsSync(videosDir)) {
fs.mkdirSync(videosDir, { recursive: true });
}
// 生成文件名:soonworker+时间戳
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
const fileName = `soonworker_${timestamp}.webm`;
const filePath = path.join(videosDir, fileName);
// 将base64数据转换为Buffer并保存
const buffer = Buffer.from(videoData.replace('data:video/webm;base64,', ''), 'base64');
fs.writeFileSync(filePath, buffer);
console.log('视频已保存到:', filePath);
return {
success: true,
filePath: filePath,
fileName: fileName,
message: '录制已保存'
};
} catch (error) {
console.error('停止录制失败:', error);
return { success: false, message: error.message };
}
}
// 获取videos目录路径
getVideosPath() {
const appPath = process.env.NODE_ENV === 'development'
? path.join(__dirname, '../../')
: path.dirname(app.getPath('exe'));
return path.join(appPath, 'videos');
}
}
// 创建录制器实例
const recorder = new ScreenRecorder();
// IPC事件处理
ipcMain.handle('start-recording', async () => {
return await recorder.startRecording();
});
ipcMain.handle('stop-recording', async (event, videoData) => {
return await recorder.stopRecording(videoData);
});
ipcMain.handle('get-videos-path', () => {
return recorder.getVideosPath();
});
// 使用全局变量方式,避免webpack模块转换问题
global.ScreenRecorderInstance = recorder;
global.setMainWindow = (window) => recorder.setMainWindow(window);
// 不导出任何内容,完全依赖全局变量
@@ -0,0 +1,198 @@
<template>
<el-dialog
:title="$t('networkAuth.title')"
:visible.sync="visible"
width="600px"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
:append-to-body="true"
:z-index="9999"
>
<div class="network-auth-content">
<p class="auth-description">
{{ $t('networkAuth.description') }}
</p>
<div class="network-paths">
<div
v-for="(path, index) in networkPaths"
:key="index"
class="network-path-item"
>
<div class="path-info">
<span class="path-label">{{ $t('networkAuth.pathLabel') }}</span>
<span class="path-value">{{ path.path }}</span>
</div>
<div class="auth-fields">
<el-input
v-model="path.userName"
:placeholder="$t('networkAuth.userName')"
size="small"
style="width: 150px; margin-right: 10px;"
/>
<el-input
v-model="path.password"
type="password"
:placeholder="$t('networkAuth.password')"
size="small"
style="width: 150px;"
show-password
/>
</div>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="handleCancel">{{ $t('networkAuth.cancel') }}</el-button>
<el-button type="primary" @click="handleConfirm" :loading="loading">
{{ $t('networkAuth.confirm') }}
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
name: 'NetworkAuthDialog',
props: {
visible: {
type: Boolean,
default: false
},
networkPaths: {
type: Array,
default: () => []
}
},
data() {
return {
loading: false
}
},
methods: {
handleCancel() {
this.$emit('cancel')
},
async handleConfirm() {
// 验证所有路径都填写了用户名和密码
for (let path of this.networkPaths) {
if (!path.userName || !path.password) {
this.$message.error(this.$t('networkAuth.authRequired'))
return
}
}
this.loading = true
try {
// 保存到本地存储
this.saveNetworkCredentials()
// 构建 net_info 数据
const netInfo = this.networkPaths.map(path => ({
host_name: this.extractHostName(path.path),
user_name: path.userName,
password: path.password
}))
this.$emit('confirm', netInfo)
} catch (error) {
console.error('保存网络认证信息失败:', error)
this.$message.error('保存认证信息失败')
} finally {
this.loading = false
}
},
extractHostName(path) {
// 从网络路径中提取主机名
// 支持格式:\\hostname\path, //hostname/path, \\192.168.1.1\path
if (path.startsWith('\\\\')) {
// Windows 网络路径 \\hostname\path
const parts = path.substring(2).split('\\')
return parts[0]
} else if (path.startsWith('//')) {
// Unix 网络路径 //hostname/path
const parts = path.substring(2).split('/')
return parts[0]
} else if (path.includes(':')) {
// 可能包含 IP 地址
const match = path.match(/^([^\\\/:]+)/)
return match ? match[1] : 'unknown'
}
return 'unknown'
},
saveNetworkCredentials() {
// 保存到 localStorage
const credentials = {}
this.networkPaths.forEach(path => {
const hostName = this.extractHostName(path.path)
credentials[hostName] = {
userName: path.userName,
password: path.password,
lastUsed: new Date().toISOString()
}
})
localStorage.setItem('networkCredentials', JSON.stringify(credentials))
// 同时保存到 Vuex store(若可用)
if (this.$store && this.$store.commit) {
this.$store.commit('SET_NETWORK_CREDENTIALS', credentials)
}
}
}
}
</script>
<style lang="less" scoped>
.network-auth-content {
.auth-description {
margin-bottom: 20px;
color: #606266;
font-size: 14px;
}
.network-paths {
.network-path-item {
border: 1px solid #e4e7ed;
border-radius: 4px;
padding: 15px;
margin-bottom: 15px;
background-color: #fafafa;
.path-info {
margin-bottom: 10px;
.path-label {
font-weight: bold;
color: #303133;
margin-right: 10px;
}
.path-value {
color: #409eff;
font-family: monospace;
background-color: #f0f9ff;
padding: 2px 6px;
border-radius: 3px;
}
}
.auth-fields {
display: flex;
align-items: center;
}
}
}
}
.dialog-footer {
text-align: right;
}
</style>
+1 -1
View File
@@ -251,7 +251,7 @@ export default {
StopOnFailure: "false" StopOnFailure: "false"
SystemSn: "830001" SystemSn: "830001"
TaskDir: "C:\\PrintTasks" TaskDir: "C:\\PrintTasks"
Version: "V3.0" Version: "V3.1"
iniparser.parse("F:\\controll\\config.ini", function (err, data) { iniparser.parse("F:\\controll\\config.ini", function (err, data) {
console.log(err); console.log(err);
+1 -1
View File
@@ -1 +1 @@
{"files":["C:\\Users\\jerry\\Desktop\\cardsoon\\卡树产品保修条款.docx"]} {"files":["\\\\NAS\\study\\research_reports\\餐饮服务\\“保健水晶鸡、鸭皮蛋”商业计划书.docx"]}
+91
View File
@@ -61,6 +61,32 @@ import archiverdialog from "./archiverdialog";
import { calcSize, getFileName, isFolder } from "./calc"; import { calcSize, getFileName, isFolder } from "./calc";
import { copy } from "./copy"; import { copy } from "./copy";
import { zip } from "./archiver"; import { zip } from "./archiver";
// 网络路径检测工具函数
const isNetworkPath = (path) => {
// 检测是否为网络路径
// Windows 网络路径: \\hostname\path 或 \\IP\path
// Unix 网络路径: //hostname/path 或 //IP/path
return path.startsWith('\\\\') || path.startsWith('//') ||
(path.includes(':') && !path.includes('\\') && !path.includes('/'));
};
const extractHostName = (path) => {
if (path.startsWith('\\\\')) {
// Windows 网络路径 \\hostname\path
const parts = path.substring(2).split('\\')
return parts[0]
} else if (path.startsWith('//')) {
// Unix 网络路径 //hostname/path
const parts = path.substring(2).split('/')
return parts[0]
} else if (path.includes(':')) {
// 可能包含 IP 地址
const match = path.match(/^([^\\\/:]+)/)
return match ? match[1] : 'unknown'
}
return 'unknown'
};
export default { export default {
name: "Files", name: "Files",
props: { props: {
@@ -96,6 +122,7 @@ export default {
isCopy: false, isCopy: false,
isSucess: true, isSucess: true,
copyPath: "", copyPath: "",
networkPaths: [], // 存储检测到的网络路径
}; };
}, },
mounted() { mounted() {
@@ -132,6 +159,12 @@ export default {
// 是文件夹 // 是文件夹
this.sizeChange(f.size); this.sizeChange(f.size);
} }
// 检测是否为网络路径
if (isNetworkPath(f.path)) {
this.addNetworkPath(f.path);
}
return true; return true;
} else { } else {
//有了,不用加入 //有了,不用加入
@@ -145,6 +178,7 @@ export default {
properties: ["multiSelections"], properties: ["multiSelections"],
}) })
.then(async (res) => { .then(async (res) => {
console.log(res)
for (const item of res.filePaths) { for (const item of res.filePaths) {
await fs.stat(item, function (err, res) { await fs.stat(item, function (err, res) {
if (err) { if (err) {
@@ -167,6 +201,7 @@ export default {
properties: ["openDirectory", "multiSelections"], properties: ["openDirectory", "multiSelections"],
}) })
.then((res) => { .then((res) => {
console.log(res)
for (const item of res.filePaths) { for (const item of res.filePaths) {
const result = _this.insertList({ const result = _this.insertList({
name: getFileName(item), name: getFileName(item),
@@ -309,6 +344,62 @@ export default {
getLists() { getLists() {
return this.filesList; return this.filesList;
}, },
// 添加网络路径到列表(按主机去重,仅认证根目录,如 \\\\NAS)
addNetworkPath(path) {
const hostName = extractHostName(path);
const existingIndex = this.networkPaths.findIndex(p => p.hostName === hostName);
if (existingIndex === -1) {
// 尝试从本地存储获取已保存的认证信息
let userName = '';
let password = '';
try {
const stored = localStorage.getItem('networkCredentials');
if (stored) {
const credentials = JSON.parse(stored);
if (credentials[hostName]) {
userName = credentials[hostName].userName;
password = credentials[hostName].password;
}
}
} catch (error) {
console.log('无法获取已保存的认证信息');
}
// 仅保存根路径用于展示与认证
const rootPath = `\\\\${hostName}`;
this.networkPaths.push({
path: rootPath,
hostName: hostName,
userName: userName,
password: password
});
}
},
// 获取网络路径列表(按主机去重,返回根路径)
getNetworkPaths() {
const uniqueByHost = {};
for (const item of this.networkPaths) {
if (!uniqueByHost[item.hostName]) {
uniqueByHost[item.hostName] = {
path: `\\\\${item.hostName}`,
hostName: item.hostName,
userName: item.userName || '',
password: item.password || ''
};
}
}
return Object.values(uniqueByHost);
},
// 检查是否有网络路径
hasNetworkPaths() {
return this.networkPaths.length > 0;
},
haveFolderIsCalc() {}, haveFolderIsCalc() {},
}, },
computed: {}, computed: {},
+93 -89
View File
@@ -210,6 +210,7 @@ export default {
}, },
onSubmituser() { onSubmituser() {
if (this.ruleForm.name == '1') { if (this.ruleForm.name == '1') {
this.setStep()
this.$router.push({ this.$router.push({
path: '/main' path: '/main'
}) })
@@ -234,95 +235,7 @@ export default {
console.log(res.data) console.log(res.data)
localStorage.setItem('loginrole', res.data.resultinfo.userRole) localStorage.setItem('loginrole', res.data.resultinfo.userRole)
localStorage.setItem('loginname', res.data.resultinfo.userName) localStorage.setItem('loginname', res.data.resultinfo.userName)
const guideStep = [ this.setStep()
{
show: false,
placement: 'right',
step: this.$t('guide.step1'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step2'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step3'),
},
{
show: false,
placement: 'left',
step: this.$t('guide.step4'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step5'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step6'),
},
{
show: false,
placement: 'top',
step: this.$t('guide.step7'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step8'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step9'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step10'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step11'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step12'),
},
{
show: false,
placement: 'left',
step: this.$t('guide.step13'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step14'),
},
{
show: false,
placement: 'top',
step: this.$t('guide.step15'),
},
{
show: false,
placement: 'top',
step: this.$t('guide.step16'),
},
{
show: false,
placement: 'top',
step: this.$t('guide.step17'),
},
]
localStorage.setItem('guideStep', JSON.stringify(guideStep))
localStorage.setItem('currentStep', 0)
this.$router.push({ this.$router.push({
path: '/main' path: '/main'
}) })
@@ -346,6 +259,97 @@ export default {
} }
}) })
}, },
setStep() {
const guideStep = [
{
show: false,
placement: 'right',
step: this.$t('guide.step1'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step2'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step3'),
},
{
show: false,
placement: 'left',
step: this.$t('guide.step4'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step5'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step6'),
},
{
show: false,
placement: 'top',
step: this.$t('guide.step7'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step8'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step9'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step10'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step11'),
},
{
show: false,
placement: 'right',
step: this.$t('guide.step12'),
},
{
show: false,
placement: 'left',
step: this.$t('guide.step13'),
},
{
show: false,
placement: 'bottom',
step: this.$t('guide.step14'),
},
{
show: false,
placement: 'top',
step: this.$t('guide.step15'),
},
{
show: false,
placement: 'top',
step: this.$t('guide.step16'),
},
{
show: false,
placement: 'top',
step: this.$t('guide.step17'),
},
]
localStorage.setItem('guideStep', JSON.stringify(guideStep))
localStorage.setItem('currentStep', 0)
},
// 监听回车键执行事件 // 监听回车键执行事件
keyDown(e) { keyDown(e) {
// 回车则执行登录方法 enter键的ASCII是13 // 回车则执行登录方法 enter键的ASCII是13
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,252 @@
<template>
<div class="screen-recorder">
<el-tooltip
:content="isRecording ? $t('recorder.stopRecording') : $t('recorder.startRecording')"
placement="top">
<el-button
:type="isRecording ? 'danger' : 'primary'"
:icon="isRecording ? 'el-icon-video-pause' : 'el-icon-video-camera'"
circle
@click="toggleRecording"
:loading="loading"
class="record-btn"
>
</el-button>
</el-tooltip>
<!-- 录制状态指示器 -->
<div v-if="isRecording" class="recording-indicator">
<span class="recording-dot"></span>
<span class="recording-text">{{ recordingTime }}</span>
</div>
</div>
</template>
<script>
const { ipcRenderer } = require('electron');
export default {
name: 'ScreenRecorder',
data() {
return {
isRecording: false,
loading: false,
mediaRecorder: null,
recordedChunks: [],
startTime: null,
recordingTime: '00:00',
timer: null,
stream: null
};
},
methods: {
async toggleRecording() {
if (this.isRecording) {
await this.stopRecording();
} else {
await this.startRecording();
}
},
async startRecording() {
this.loading = true;
try {
// 调用主进程开始录制
const result = await ipcRenderer.invoke('start-recording');
if (!result.success) {
this.$message.error(result.message);
this.loading = false;
return;
}
// 获取屏幕流
const stream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: result.sourceId,
minWidth: 1280,
maxWidth: 1920,
minHeight: 720,
maxHeight: 1080
}
}
});
this.stream = stream;
this.recordedChunks = [];
// 创建MediaRecorder
this.mediaRecorder = new MediaRecorder(stream, {
mimeType: 'video/webm'
});
this.mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
this.recordedChunks.push(event.data);
}
};
this.mediaRecorder.onstop = async () => {
await this.saveRecording();
};
// 开始录制
this.mediaRecorder.start();
this.isRecording = true;
this.startTime = Date.now();
this.startTimer();
this.$message.success(this.$t('recorder.recordingStarted') || '开始录制');
this.$emit('recording-started');
} catch (error) {
console.error('启动录制失败:', error);
this.$message.error(this.$t('recorder.startFailed') || '启动录制失败');
} finally {
this.loading = false;
}
},
async stopRecording() {
this.loading = true;
try {
if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
this.mediaRecorder.stop();
}
// 停止所有轨道
if (this.stream) {
this.stream.getTracks().forEach(track => track.stop());
this.stream = null;
}
this.isRecording = false;
this.stopTimer();
this.$emit('recording-stopped');
} catch (error) {
console.error('停止录制失败:', error);
this.$message.error(this.$t('recorder.stopFailed') || '停止录制失败');
} finally {
this.loading = false;
}
},
async saveRecording() {
if (this.recordedChunks.length === 0) {
return;
}
try {
// 将录制的数据块合并为Blob
const blob = new Blob(this.recordedChunks, {
type: 'video/webm'
});
// 转换为base64
const reader = new FileReader();
reader.onloadend = async () => {
const base64data = reader.result;
// 发送到主进程保存
const result = await ipcRenderer.invoke('stop-recording', base64data);
if (result.success) {
this.$message.success(this.$t('recorder.savedSuccess') || `录制已保存: ${result.fileName}`);
this.$emit('recording-saved', result);
} else {
this.$message.error(result.message);
}
};
reader.readAsDataURL(blob);
} catch (error) {
console.error('保存录制失败:', error);
this.$message.error(this.$t('recorder.saveFailed') || '保存录制失败');
}
},
startTimer() {
this.timer = setInterval(() => {
const elapsed = Math.floor((Date.now() - this.startTime) / 1000);
const minutes = Math.floor(elapsed / 60).toString().padStart(2, '0');
const seconds = (elapsed % 60).toString().padStart(2, '0');
this.recordingTime = `${minutes}:${seconds}`;
}, 1000);
},
stopTimer() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
this.recordingTime = '00:00';
}
},
// 外部调用的方法,用于在提交作业时自动停止录制
async stopIfRecording() {
if (this.isRecording) {
await this.stopRecording();
}
}
},
beforeDestroy() {
// 组件销毁时确保停止录制
if (this.isRecording) {
this.stopRecording();
}
}
};
</script>
<style lang="less" scoped>
.screen-recorder {
display: inline-flex;
align-items: center;
gap: 10px;
.record-btn {
&:hover {
transform: scale(1.1);
}
}
.recording-indicator {
display: flex;
align-items: center;
gap: 5px;
padding: 5px 10px;
background: rgba(245, 108, 108, 0.1);
border-radius: 15px;
.recording-dot {
width: 8px;
height: 8px;
background: #f56c6c;
border-radius: 50%;
animation: blink 1s infinite;
}
.recording-text {
font-size: 14px;
color: #f56c6c;
font-weight: 500;
}
}
}
@keyframes blink {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.3;
}
}
</style>
+120 -3
View File
@@ -251,6 +251,22 @@
{{ $t('work.senior') }} {{ $t('work.senior') }}
</el-button> </el-button>
</el-popover> </el-popover>
<!-- 屏幕录制按钮 -->
<screen-recorder
ref="screenRecorder"
@recording-started="onRecordingStarted"
@recording-stopped="onRecordingStopped"
@recording-saved="onRecordingSaved"
style="margin-left: 10px; display: inline-block;"
/>
<!-- 网络路径认证对话框 -->
<network-auth-dialog
:visible="networkAuthVisible"
:network-paths="networkAuthPaths"
@confirm="onNetworkAuthConfirm"
@cancel="onNetworkAuthCancel"
/>
</div> </div>
</div> </div>
<el-row <el-row
@@ -1145,6 +1161,8 @@ function getNowFormatDate() {
return currentdate return currentdate
} }
import Files from './files/file.vue' import Files from './files/file.vue'
import ScreenRecorder from './recorder/ScreenRecorder.vue'
import NetworkAuthDialog from './NetworkAuthDialog.vue'
let fs = require('fs') let fs = require('fs')
let path = require('path') let path = require('path')
const { app, dialog } = require('@electron/remote') const { app, dialog } = require('@electron/remote')
@@ -1182,10 +1200,17 @@ export default {
} }
}, },
components: { components: {
Files Files,
ScreenRecorder,
NetworkAuthDialog
}, },
data() { data() {
return { return {
// 网络路径认证相关
networkAuthVisible: false,
networkAuthPaths: [],
networkCredentials: {},
// 模板列表 // 模板列表
templates: [], templates: [],
currentTemplate: '', currentTemplate: '',
@@ -1392,10 +1417,77 @@ export default {
this.guideStep[this.currentStep].show = true this.guideStep[this.currentStep].show = true
}, 200) }, 200)
} }
// 加载网络认证信息
this.loadNetworkCredentials()
this.getTemplates() this.getTemplates()
}, },
updated() {}, updated() {},
methods: { methods: {
// 录制相关方法
onRecordingStarted() {
console.log('录制已开始')
},
onRecordingStopped() {
console.log('录制已停止')
},
onRecordingSaved(result) {
console.log('录制已保存:', result)
this.$message.success(`录制已保存: ${result.fileName}`)
},
async stopRecordingIfActive() {
// 如果正在录制,则停止录制
if (this.$refs.screenRecorder) {
await this.$refs.screenRecorder.stopIfRecording()
}
},
// 网络路径认证相关方法
loadNetworkCredentials() {
try {
const stored = localStorage.getItem('networkCredentials')
if (stored) {
this.networkCredentials = JSON.parse(stored)
}
} catch (error) {
console.error('加载网络认证信息失败:', error)
}
},
// 检查是否有网络路径需要认证
checkNetworkPaths() {
if (this.$refs.files && this.$refs.files.hasNetworkPaths()) {
const networkPaths = this.$refs.files.getNetworkPaths()
if (networkPaths.length > 0) {
this.networkAuthPaths = networkPaths
this.networkAuthVisible = true
return true
}
}
return false
},
// 网络认证确认回调
onNetworkAuthConfirm(netInfo) {
this.networkCredentials = netInfo
this.networkAuthVisible = false
// 继续提交流程
this.continueSubmit()
},
// 网络认证取消回调
onNetworkAuthCancel() {
this.networkAuthVisible = false
this.$message.info(this.$t('networkAuth.authCanceled'))
},
// 继续提交流程
continueSubmit() {
// 这里继续原来的提交逻辑
this.performSubmit()
},
addFolder() { addFolder() {
this.$refs.files.addFolder() this.$refs.files.addFolder()
}, },
@@ -2025,7 +2117,21 @@ export default {
//}, 0); //}, 0);
//console.log(1); //console.log(1);
}, },
submit() { async submit() {
// 停止录制(如果正在录制)
await this.stopRecordingIfActive()
// 检查是否有网络路径需要认证
if (this.checkNetworkPaths()) {
return // 等待用户完成网络认证
}
// 继续提交流程
this.performSubmit()
},
// 实际的提交逻辑
async performSubmit() {
//提交最终的任务请求 //提交最终的任务请求
let data = '' let data = ''
let pathName let pathName
@@ -2201,6 +2307,12 @@ export default {
if (this.high_setting_form.formatFile != 0) { if (this.high_setting_form.formatFile != 0) {
data += '&formatFile=' + this.high_setting_form.formatFile //拷贝前类型 data += '&formatFile=' + this.high_setting_form.formatFile //拷贝前类型
} }
// 添加网络路径认证信息
if (this.networkCredentials && this.networkCredentials.length > 0) {
data += '&net_info=' + JSON.stringify(this.networkCredentials)
}
// if (this.file_form == 0 || this.file_form == 1 || this.file_form == 4 || this.file_form == 2 || this.file_form == 3 || this.file_form == 7) { // if (this.file_form == 0 || this.file_form == 1 || this.file_form == 4 || this.file_form == 2 || this.file_form == 3 || this.file_form == 7) {
// } else { // } else {
@@ -2286,6 +2398,11 @@ export default {
// 使用FormData上传文件 // 使用FormData上传文件
const formData = new FormData() const formData = new FormData()
formData.append('file', blob, path.basename(jsonFilePath)) formData.append('file', blob, path.basename(jsonFilePath))
// 添加网络路径认证信息
if (this.networkCredentials && this.networkCredentials.length > 0) {
formData.append('net_info', JSON.stringify(this.networkCredentials))
}
that.submitLoading = true that.submitLoading = true
// 发送HTTP请求上传文件 // 发送HTTP请求上传文件
that that
@@ -2517,7 +2634,7 @@ export default {
computed: { computed: {
file_percent() { file_percent() {
let t = (this.size / (((this.size_form * 1000) / 1.024 / 1.024 / 1.024) * 1024 * 1024)) * 100 let t = (this.size / (((this.size_form * 1000) / 1.024 / 1.024 / 1.024) * 1024 * 1024)) * 100
return t > 100 ? 100.1 : t return t ? t > 100 ? 100.1 : t : 0
}, },
print_op() { print_op() {
return [ return [
+1 -1
View File
@@ -1637,7 +1637,7 @@ export default {
(this.size / (this.size /
(((this.size_form * 1000) / 1.024 / 1.024 / 1.024) * 1024 * 1024)) * (((this.size_form * 1000) / 1.024 / 1.024 / 1.024) * 1024 * 1024)) *
100; 100;
return t > 100 ? 100.1 : t; return t ? t > 100 ? 100.1 : t : 0
}, },
print_op() { print_op() {
return [ return [
+23 -1
View File
@@ -1,4 +1,26 @@
export default { export default {
recorder: {
startRecording: "开始录制",
stopRecording: "停止录制",
recordingStarted: "开始录制屏幕",
recordingStopped: "录制已停止",
savedSuccess: "录制已保存",
startFailed: "启动录制失败",
stopFailed: "停止录制失败",
saveFailed: "保存录制失败"
},
networkAuth: {
title: "网络路径认证",
description: "检测到以下网络路径,请输入对应的用户名和密码:",
pathLabel: "网络路径:",
userName: "用户名",
password: "密码",
confirm: "确认",
cancel: "取消",
authRequired: "请填写所有网络路径的用户名和密码",
authSuccess: "网络认证信息已保存",
authCanceled: "已取消网络路径认证"
},
finger: { finger: {
intTips: "指纹模块正在初始化", intTips: "指纹模块正在初始化",
errorInttips: "指纹模块初始化失败", errorInttips: "指纹模块初始化失败",
@@ -18,7 +40,7 @@ export default {
login: "登录", login: "登录",
fingerLogin: "使用指纹登录", fingerLogin: "使用指纹登录",
title1: "CARDSOON USB存储卡", title1: "CARDSOON USB存储卡",
title2: "自动拷贝打印系统 V3.0", title2: "自动拷贝打印系统 V3.1",
successLogin: "登录成功!", successLogin: "登录成功!",
errorFingerlogin: "登录失败,请重试指纹!", errorFingerlogin: "登录失败,请重试指纹!",
errorLogin: "登录失败,请检查账号密码!", errorLogin: "登录失败,请检查账号密码!",
+22
View File
@@ -1,4 +1,26 @@
export default { export default {
recorder: {
startRecording: "Start Recording",
stopRecording: "Stop Recording",
recordingStarted: "Screen recording started",
recordingStopped: "Recording stopped",
savedSuccess: "Recording saved",
startFailed: "Failed to start recording",
stopFailed: "Failed to stop recording",
saveFailed: "Failed to save recording"
},
networkAuth: {
title: "Network Path Authentication",
description: "The following network paths were detected. Please enter the corresponding username and password:",
pathLabel: "Network Path:",
userName: "Username",
password: "Password",
confirm: "Confirm",
cancel: "Cancel",
authRequired: "Please fill in username and password for all network paths",
authSuccess: "Network authentication information saved",
authCanceled: "Network path authentication canceled"
},
finger: { finger: {
intTips: "The fingerprint module is initializing", intTips: "The fingerprint module is initializing",
errorInttips: "Fingerprint module initialization fail", errorInttips: "Fingerprint module initialization fail",
+1 -1
View File
@@ -17,7 +17,7 @@ export default {
login:"登入", login:"登入",
fingerLogin:"使用指紋登入", fingerLogin:"使用指紋登入",
title1:"CARDSOON USB存儲卡", title1:"CARDSOON USB存儲卡",
title2:"自動拷貝列印系統V3.0", title2:"自動拷貝列印系統V3.1",
successLogin:"登入成功! ", successLogin:"登入成功! ",
errorFingerlogin:"登入失敗,請重試指紋! ", errorFingerlogin:"登入失敗,請重試指紋! ",
errorLogin:"登入失敗,請檢查帳號密碼! ", errorLogin:"登入失敗,請檢查帳號密碼! ",
+70
View File
@@ -0,0 +1,70 @@
const state = {
networkCredentials: {}
}
const mutations = {
SET_NETWORK_CREDENTIALS(state, credentials) {
state.networkCredentials = { ...state.networkCredentials, ...credentials }
},
CLEAR_NETWORK_CREDENTIALS(state) {
state.networkCredentials = {}
},
UPDATE_NETWORK_CREDENTIAL(state, { hostName, credentials }) {
state.networkCredentials = {
...state.networkCredentials,
[hostName]: credentials
}
}
}
const actions = {
// 从 localStorage 加载网络认证信息
loadNetworkCredentials({ commit }) {
try {
const stored = localStorage.getItem('networkCredentials')
if (stored) {
const credentials = JSON.parse(stored)
commit('SET_NETWORK_CREDENTIALS', credentials)
}
} catch (error) {
console.error('加载网络认证信息失败:', error)
}
},
// 保存网络认证信息到 localStorage
saveNetworkCredentials({ state }) {
try {
localStorage.setItem('networkCredentials', JSON.stringify(state.networkCredentials))
} catch (error) {
console.error('保存网络认证信息失败:', error)
}
},
// 获取指定主机的认证信息
getCredentialsForHost({ state }, hostName) {
return state.networkCredentials[hostName] || null
},
// 更新指定主机的认证信息
updateCredentialsForHost({ commit }, { hostName, credentials }) {
commit('UPDATE_NETWORK_CREDENTIAL', { hostName, credentials })
}
}
const getters = {
// 获取所有网络认证信息
allNetworkCredentials: state => state.networkCredentials,
// 检查是否有网络认证信息
hasNetworkCredentials: state => Object.keys(state.networkCredentials).length > 0
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
Binary file not shown.