Skip to content

Commit d960d89

Browse files
committed
新增:工单反馈功能,便于解决问题
1 parent 2ced498 commit d960d89

21 files changed

Lines changed: 342 additions & 23 deletions

File tree

electron/config/window.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export const WindowConfig = {
1111
pluginHeight: 500,
1212
aboutWidth: 500,
1313
aboutHeight: 400,
14+
feedbackWidth: 600,
15+
feedbackHeight: 600,
1416
guideWidth: 800,
1517
guideHeight: 540,
1618
setupWidth: 800,

electron/mapi/app/main.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import {app, BrowserWindow, ipcMain, screen, shell, clipboard, nativeImage, nativeTheme} from "electron";
1+
import {app, BrowserWindow, clipboard, ipcMain, nativeImage, nativeTheme, screen, shell} from "electron";
22
import {WindowConfig} from "../../config/window";
33
import {AppRuntime} from "../env";
4-
import {isDev, isMac} from "../../lib/env";
4+
import {isDev, isMac, platformArch, platformName} from "../../lib/env";
55
import {AppPosition} from "./lib/position";
66
import {Events} from "../event/main";
77
import {ConfigMain} from "../config/main";
@@ -318,6 +318,17 @@ ipcMain.handle('app:getBuildInfo', async () => {
318318
return getBuildInfo()
319319
})
320320

321+
const collect = async (options?: {}) => {
322+
return {
323+
platformName: platformName(),
324+
platformArch: platformArch(),
325+
}
326+
}
327+
328+
ipcMain.handle('app:collect', async (event, options?: {}) => {
329+
return collect(options)
330+
})
331+
321332
export default {
322333
quit
323334
}

electron/mapi/app/render.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ const appEnv = async () => {
7676
return AppEnv
7777
}
7878

79+
const setRenderAppEnv = (env: any) => {
80+
AppEnv.isInit = true
81+
AppEnv.appRoot = env.appRoot
82+
AppEnv.appData = env.appData
83+
AppEnv.userData = env.userData
84+
}
85+
7986
const getClipboardText = () => {
8087
return ipcRenderer.invoke('app:getClipboardText')
8188
}
@@ -112,6 +119,10 @@ const getBuildInfo = async () => {
112119
return ipcRenderer.invoke('app:getBuildInfo')
113120
}
114121

122+
const collect = async (options?: {}) => {
123+
return ipcRenderer.invoke('app:collect', options)
124+
}
125+
115126
export const AppsRender = {
116127
isDarkMode,
117128
resourcePathResolve,
@@ -131,6 +142,7 @@ export const AppsRender = {
131142
openExternalWeb,
132143
getPreload,
133144
appEnv,
145+
setRenderAppEnv,
134146
getClipboardText,
135147
setClipboardText,
136148
getClipboardImage,
@@ -140,6 +152,7 @@ export const AppsRender = {
140152
setupOpen,
141153
setupIsOk,
142154
getBuildInfo,
155+
collect,
143156
shell: appIndex.shell,
144157
spawnShell: appIndex.spawnShell,
145158
availablePort: appIndex.availablePort,

electron/mapi/file/index.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,43 @@ const readBuffer = async (path: string, option?: { isFullPath?: boolean, }): Pro
214214
})
215215
}
216216

217+
const readLine = async (path: string, callback: (line: string) => void, option?: {
218+
isFullPath?: boolean,
219+
}) => {
220+
option = Object.assign({
221+
isFullPath: false,
222+
}, option)
223+
let fp = path
224+
if (!option.isFullPath) {
225+
fp = await fullPath(path)
226+
}
227+
if (!fs.existsSync(fp)) {
228+
return
229+
}
230+
return new Promise((resolve, reject) => {
231+
const f = fs.createReadStream(fp)
232+
let remaining = ''
233+
f.on('data', (chunk) => {
234+
remaining += chunk
235+
let index = remaining.indexOf('\n')
236+
let last = 0
237+
while (index > -1) {
238+
let line = remaining.substring(last, index)
239+
last = index + 1
240+
callback(line)
241+
index = remaining.indexOf('\n', last)
242+
}
243+
remaining = remaining.substring(last)
244+
})
245+
f.on('end', () => {
246+
if (remaining.length > 0) {
247+
callback(remaining)
248+
}
249+
resolve(undefined)
250+
})
251+
})
252+
}
253+
217254
const deletes = async (path: string, option?: { isFullPath?: boolean, }) => {
218255
option = Object.assign({
219256
isFullPath: false,
@@ -520,7 +557,7 @@ const download = async (url: string, path: string, option?: {
520557
})
521558
}
522559

523-
export default {
560+
export const FileIndex = {
524561
fullPath,
525562
absolutePath,
526563
exists,
@@ -532,6 +569,7 @@ export default {
532569
writeBuffer,
533570
read,
534571
readBuffer,
572+
readLine,
535573
deletes,
536574
rename,
537575
copy,
@@ -541,3 +579,5 @@ export default {
541579
appendText,
542580
download,
543581
}
582+
583+
export default FileIndex

electron/mapi/log/index.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import date from "date-and-time";
33
import path from "node:path";
44
import {AppEnv} from "../env";
55
import fs from "node:fs";
6+
import dayjs from "dayjs";
7+
import FileIndex from "../file";
68

79
let fileName = null
810
let fileStream = null
@@ -43,7 +45,7 @@ const cleanOldLogs = (keepDays: number) => {
4345
for (let file of files) {
4446
const filePath = path.join(logDir, file)
4547
let date = null
46-
for (let s of file.split('_')) {
48+
for (let s of file.split(/[_\\.]/)) {
4749
// 匹配 YYYYMMDD
4850
if (s.match(/^\d{8}$/)) {
4951
date = s
@@ -117,13 +119,80 @@ const errorRenderOrMain = (label: string, data: any = null) => {
117119
}
118120
}
119121

122+
const collectRenderOrMain = async (option?: {
123+
startTime?: string,
124+
endTime?: string,
125+
limit?: number,
126+
}) => {
127+
option = Object.assign({
128+
startTime: dayjs().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'),
129+
endTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
130+
limit: 10 * 10000,
131+
}, option)
132+
let startMs = dayjs(option.startTime).valueOf()
133+
let endMs = dayjs(option.endTime).valueOf()
134+
let startDayMs = dayjs(option.startTime).startOf('day').valueOf()
135+
let endDayMs = dayjs(option.endTime).endOf('day').valueOf()
136+
let resultLines = []
137+
let logFiles = []
138+
logFiles = logFiles.concat(await FileIndex.list(logsDir(), {isFullPath: true}))
139+
logFiles = logFiles.concat(await FileIndex.list(appLogsDir(), {isFullPath: true}))
140+
// console.log('logFiles', logFiles)
141+
logFiles = logFiles.filter((logFile) => {
142+
if (logFile.isDirectory) {
143+
return false
144+
}
145+
let date = null
146+
for (let s of logFile.name.split(/[_\\.]/)) {
147+
// 匹配 YYYYMMDD
148+
if (s.match(/^\d{8}$/)) {
149+
date = s
150+
break
151+
}
152+
}
153+
if (!date) {
154+
return false
155+
}
156+
const fileDate = new Date(
157+
parseInt(date.substring(0, 4)),
158+
parseInt(date.substring(4, 6)) - 1,
159+
parseInt(date.substring(6, 8))
160+
)
161+
if (fileDate.getTime() < startDayMs || fileDate.getTime() > endDayMs) {
162+
return false
163+
}
164+
return true
165+
})
166+
// console.log('collectRenderOrMain', {
167+
// ...option,
168+
// logFiles, startMs, endMs, startDayMs, endDayMs
169+
// })
170+
for (const logFile of logFiles) {
171+
await FileIndex.readLine(logFile.pathname, (line) => {
172+
const lineParts = line.split(' - ')
173+
const lineTime = dayjs(lineParts[0])
174+
// console.log('lineTime', lineParts[0], lineTime.isBefore(startMs) || lineTime.isAfter(endMs))
175+
if (lineTime.isBefore(startMs) || lineTime.isAfter(endMs)) {
176+
return
177+
}
178+
resultLines.push(line)
179+
}, {isFullPath: true})
180+
}
181+
return {
182+
startTime: option.startTime,
183+
endTime: option.endTime,
184+
logs: resultLines.join("\n"),
185+
}
186+
}
187+
120188

121189
export default {
122190
root,
123191
info,
124192
error,
125193
infoRenderOrMain,
126194
errorRenderOrMain,
195+
collectRenderOrMain,
127196
}
128197

129198
export const Log = {

electron/mapi/log/render.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export default {
44
root: logIndex.root,
55
info: logIndex.infoRenderOrMain,
66
error: logIndex.errorRenderOrMain,
7+
collect: logIndex.collectRenderOrMain,
78
}

electron/page/feedback.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {BrowserWindow} from "electron";
2+
import {preloadDefault} from "../lib/env-main";
3+
import {AppRuntime} from "../mapi/env";
4+
import {t} from "../config/lang";
5+
import {Page} from "./index";
6+
import {WindowConfig} from "../config/window";
7+
8+
export const PageFeedback = {
9+
NAME: 'feedback',
10+
open: async (option: any) => {
11+
const win = new BrowserWindow({
12+
title: t('工单反馈'),
13+
parent: AppRuntime.mainWindow,
14+
minWidth: WindowConfig.feedbackWidth,
15+
minHeight: WindowConfig.feedbackHeight,
16+
width: WindowConfig.feedbackWidth,
17+
height: WindowConfig.feedbackHeight,
18+
webPreferences: {
19+
preload: preloadDefault,
20+
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
21+
nodeIntegration: true,
22+
webSecurity: false,
23+
webviewTag: true,
24+
// Consider using contextBridge.exposeInMainWorld
25+
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
26+
contextIsolation: false,
27+
},
28+
show: true,
29+
frame: false,
30+
transparent: false,
31+
});
32+
return Page.openWindow(PageFeedback.NAME, win, "page/feedback.html");
33+
}
34+
}

electron/page/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import {PageGuide} from "./guide";
77
import {PageSetup} from "./setup";
88
import {PageAbout} from "./about";
99
import {DevToolsManager} from "../lib/devtools";
10+
import {PageFeedback} from "./feedback";
1011

1112
const Pages = {
1213
'user': PageUser,
1314
'guide': PageGuide,
1415
'setup': PageSetup,
1516
'about': PageAbout,
17+
'feedback': PageFeedback,
1618
}
1719

1820
export const Page = {

page/feedback.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8"/>
5+
<link rel="icon" type="image/svg+xml" href="/logo.svg"/>
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
7+
<title>%name%</title>
8+
<link rel="stylesheet" href="./../iconfont/iconfont.css"/>
9+
</head>
10+
<body>
11+
<div id="app"></div>
12+
<script type="module" src="/src/entry/feedback.ts"></script>
13+
</body>
14+
</html>

src/components/Setting/SettingAbout.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const doOpenLog = async () => {
3838
target="_blank"
3939
class="align-top arco-btn arco-btn-secondary arco-btn-shape-square arco-btn-size-medium arco-btn-status-normal ml-3">
4040
<icon-customer-service class="mr-1"/>
41-
{{ t('使用反馈') }}
41+
{{ t('工单反馈') }}
4242
</a>
4343
<a-button class="ml-3"
4444
@click="doOpenLog">

0 commit comments

Comments
 (0)