录制和网络路径
This commit is contained in:
@@ -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>
|
||||
@@ -251,7 +251,7 @@ export default {
|
||||
StopOnFailure: "false"
|
||||
SystemSn: "830001"
|
||||
TaskDir: "C:\\PrintTasks"
|
||||
Version: "V3.0"
|
||||
Version: "V3.1"
|
||||
|
||||
iniparser.parse("F:\\controll\\config.ini", function (err, data) {
|
||||
console.log(err);
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"files":["C:\\Users\\jerry\\Desktop\\cardsoon\\卡树产品保修条款.docx"]}
|
||||
{"files":["\\\\NAS\\study\\research_reports\\餐饮服务\\“保健水晶鸡、鸭皮蛋”商业计划书.docx"]}
|
||||
@@ -61,6 +61,32 @@ import archiverdialog from "./archiverdialog";
|
||||
import { calcSize, getFileName, isFolder } from "./calc";
|
||||
import { copy } from "./copy";
|
||||
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 {
|
||||
name: "Files",
|
||||
props: {
|
||||
@@ -96,6 +122,7 @@ export default {
|
||||
isCopy: false,
|
||||
isSucess: true,
|
||||
copyPath: "",
|
||||
networkPaths: [], // 存储检测到的网络路径
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
@@ -132,6 +159,12 @@ export default {
|
||||
// 是文件夹
|
||||
this.sizeChange(f.size);
|
||||
}
|
||||
|
||||
// 检测是否为网络路径
|
||||
if (isNetworkPath(f.path)) {
|
||||
this.addNetworkPath(f.path);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
//有了,不用加入
|
||||
@@ -145,6 +178,7 @@ export default {
|
||||
properties: ["multiSelections"],
|
||||
})
|
||||
.then(async (res) => {
|
||||
console.log(res)
|
||||
for (const item of res.filePaths) {
|
||||
await fs.stat(item, function (err, res) {
|
||||
if (err) {
|
||||
@@ -167,6 +201,7 @@ export default {
|
||||
properties: ["openDirectory", "multiSelections"],
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res)
|
||||
for (const item of res.filePaths) {
|
||||
const result = _this.insertList({
|
||||
name: getFileName(item),
|
||||
@@ -309,6 +344,62 @@ export default {
|
||||
getLists() {
|
||||
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() {},
|
||||
},
|
||||
computed: {},
|
||||
|
||||
@@ -210,6 +210,7 @@ export default {
|
||||
},
|
||||
onSubmituser() {
|
||||
if (this.ruleForm.name == '1') {
|
||||
this.setStep()
|
||||
this.$router.push({
|
||||
path: '/main'
|
||||
})
|
||||
@@ -234,95 +235,7 @@ export default {
|
||||
console.log(res.data)
|
||||
localStorage.setItem('loginrole', res.data.resultinfo.userRole)
|
||||
localStorage.setItem('loginname', res.data.resultinfo.userName)
|
||||
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)
|
||||
this.setStep()
|
||||
this.$router.push({
|
||||
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) {
|
||||
// 回车则执行登录方法 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>
|
||||
@@ -251,6 +251,22 @@
|
||||
{{ $t('work.senior') }}
|
||||
</el-button>
|
||||
</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>
|
||||
<el-row
|
||||
@@ -1145,6 +1161,8 @@ function getNowFormatDate() {
|
||||
return currentdate
|
||||
}
|
||||
import Files from './files/file.vue'
|
||||
import ScreenRecorder from './recorder/ScreenRecorder.vue'
|
||||
import NetworkAuthDialog from './NetworkAuthDialog.vue'
|
||||
let fs = require('fs')
|
||||
let path = require('path')
|
||||
const { app, dialog } = require('@electron/remote')
|
||||
@@ -1182,10 +1200,17 @@ export default {
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Files
|
||||
Files,
|
||||
ScreenRecorder,
|
||||
NetworkAuthDialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 网络路径认证相关
|
||||
networkAuthVisible: false,
|
||||
networkAuthPaths: [],
|
||||
networkCredentials: {},
|
||||
|
||||
// 模板列表
|
||||
templates: [],
|
||||
currentTemplate: '',
|
||||
@@ -1392,10 +1417,77 @@ export default {
|
||||
this.guideStep[this.currentStep].show = true
|
||||
}, 200)
|
||||
}
|
||||
|
||||
// 加载网络认证信息
|
||||
this.loadNetworkCredentials()
|
||||
|
||||
this.getTemplates()
|
||||
},
|
||||
updated() {},
|
||||
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() {
|
||||
this.$refs.files.addFolder()
|
||||
},
|
||||
@@ -2025,7 +2117,21 @@ export default {
|
||||
//}, 0);
|
||||
//console.log(1);
|
||||
},
|
||||
submit() {
|
||||
async submit() {
|
||||
// 停止录制(如果正在录制)
|
||||
await this.stopRecordingIfActive()
|
||||
|
||||
// 检查是否有网络路径需要认证
|
||||
if (this.checkNetworkPaths()) {
|
||||
return // 等待用户完成网络认证
|
||||
}
|
||||
|
||||
// 继续提交流程
|
||||
this.performSubmit()
|
||||
},
|
||||
|
||||
// 实际的提交逻辑
|
||||
async performSubmit() {
|
||||
//提交最终的任务请求
|
||||
let data = ''
|
||||
let pathName
|
||||
@@ -2201,6 +2307,12 @@ export default {
|
||||
if (this.high_setting_form.formatFile != 0) {
|
||||
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) {
|
||||
|
||||
// } else {
|
||||
@@ -2286,6 +2398,11 @@ export default {
|
||||
// 使用FormData上传文件
|
||||
const formData = new FormData()
|
||||
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
|
||||
// 发送HTTP请求上传文件
|
||||
that
|
||||
@@ -2517,7 +2634,7 @@ export default {
|
||||
computed: {
|
||||
file_percent() {
|
||||
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() {
|
||||
return [
|
||||
|
||||
@@ -1637,7 +1637,7 @@ export default {
|
||||
(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() {
|
||||
return [
|
||||
|
||||
+23
-1
@@ -1,4 +1,26 @@
|
||||
export default {
|
||||
recorder: {
|
||||
startRecording: "开始录制",
|
||||
stopRecording: "停止录制",
|
||||
recordingStarted: "开始录制屏幕",
|
||||
recordingStopped: "录制已停止",
|
||||
savedSuccess: "录制已保存",
|
||||
startFailed: "启动录制失败",
|
||||
stopFailed: "停止录制失败",
|
||||
saveFailed: "保存录制失败"
|
||||
},
|
||||
networkAuth: {
|
||||
title: "网络路径认证",
|
||||
description: "检测到以下网络路径,请输入对应的用户名和密码:",
|
||||
pathLabel: "网络路径:",
|
||||
userName: "用户名",
|
||||
password: "密码",
|
||||
confirm: "确认",
|
||||
cancel: "取消",
|
||||
authRequired: "请填写所有网络路径的用户名和密码",
|
||||
authSuccess: "网络认证信息已保存",
|
||||
authCanceled: "已取消网络路径认证"
|
||||
},
|
||||
finger: {
|
||||
intTips: "指纹模块正在初始化",
|
||||
errorInttips: "指纹模块初始化失败",
|
||||
@@ -18,7 +40,7 @@ export default {
|
||||
login: "登录",
|
||||
fingerLogin: "使用指纹登录",
|
||||
title1: "CARDSOON USB存储卡",
|
||||
title2: "自动拷贝打印系统 V3.0",
|
||||
title2: "自动拷贝打印系统 V3.1",
|
||||
successLogin: "登录成功!",
|
||||
errorFingerlogin: "登录失败,请重试指纹!",
|
||||
errorLogin: "登录失败,请检查账号密码!",
|
||||
|
||||
@@ -1,4 +1,26 @@
|
||||
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: {
|
||||
intTips: "The fingerprint module is initializing",
|
||||
errorInttips: "Fingerprint module initialization fail",
|
||||
|
||||
@@ -17,7 +17,7 @@ export default {
|
||||
login:"登入",
|
||||
fingerLogin:"使用指紋登入",
|
||||
title1:"CARDSOON USB存儲卡",
|
||||
title2:"自動拷貝列印系統V3.0",
|
||||
title2:"自動拷貝列印系統V3.1",
|
||||
successLogin:"登入成功! ",
|
||||
errorFingerlogin:"登入失敗,請重試指紋! ",
|
||||
errorLogin:"登入失敗,請檢查帳號密碼! ",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user