diff --git a/packages/desktop/electron/main/config.ts b/packages/desktop/electron/main/config.ts deleted file mode 100644 index c17a72d6..00000000 --- a/packages/desktop/electron/main/config.ts +++ /dev/null @@ -1,105 +0,0 @@ -import jsonfile from 'jsonfile'; -import * as fs from 'node:fs'; -import { v5 as uuidv5 } from 'uuid'; -import dayjs from 'dayjs'; -import { PEAR_FILES_PATH, CONFIG_FILE_PATH, DEFAULT_CONFIG_FILE_PATH } from './contract'; - -export function initConfig() { - if (!fs.existsSync(PEAR_FILES_PATH)) { - fs.mkdirSync(PEAR_FILES_PATH, { recursive: true }); - } - fs.access(DEFAULT_CONFIG_FILE_PATH, fs.constants.F_OK, (err) => { - if (err) { - initDefaultConfig(); - return; - } - }); -} - -function initDefaultConfig() { - const defaultConfig = { - user: { - uuid: uuidv5('https://www.w3.org/', uuidv5.URL), - userName: `pear-rec:user`, - userType: 1, - createdAt: dayjs().format(), - }, - isProxy: false, - proxyPort: '7890', - language: 'zh', - filePath: PEAR_FILES_PATH, - openAtLogin: false, - serverPath: 'http://localhost:9190/', - }; - jsonfile.writeFileSync(CONFIG_FILE_PATH, defaultConfig, { - spaces: 2, - EOL: '\r\n', - }); - jsonfile.writeFileSync(DEFAULT_CONFIG_FILE_PATH, defaultConfig, { - spaces: 2, - EOL: '\r\n', - }); -} - -export function getConfig() { - try { - let config = jsonfile.readFileSync(CONFIG_FILE_PATH) || {}; - return config; - } catch (err) { - console.log('getConfig :', err); - } -} - -export function getDefaultConfig() { - try { - let defaultConfig = jsonfile.readFileSync(DEFAULT_CONFIG_FILE_PATH) || {}; - return defaultConfig; - } catch (err) { - console.log('getConfig :', err); - } -} - -export function resetConfig() { - try { - let defaultConfig = jsonfile.readFileSync(DEFAULT_CONFIG_FILE_PATH) || {}; - jsonfile.writeFileSync(CONFIG_FILE_PATH, defaultConfig, { - spaces: 2, - EOL: '\r\n', - }); - return defaultConfig; - } catch (err) { - console.log('getConfig :', err); - } -} - -export function editConfig(key: string, value: any, cb?: Function) { - try { - let config = jsonfile.readFileSync(CONFIG_FILE_PATH) || {}; - config[key] = value; - jsonfile - .writeFile(CONFIG_FILE_PATH, config, { - spaces: 2, - EOL: '\r\n', - }) - .then(() => { - cb && cb(); - }); - return config; - } catch (err) { - console.log('editConfig :', err); - } -} - -export function editUser(key: string, value: string, cb?: Function) { - try { - jsonfile.readFile(CONFIG_FILE_PATH).then((config) => { - const user = config.user; - user[key] = value; - jsonfile.writeFile(CONFIG_FILE_PATH, { user: user }, { spaces: 2, EOL: '\r\n' }).then(() => { - cb && cb(); - }); - }); - } catch (err) { - console.log('editUser :', err); - } -} diff --git a/packages/desktop/electron/main/contract.ts b/packages/desktop/electron/main/contract.ts index b6fa4b44..fc5ab801 100644 --- a/packages/desktop/electron/main/contract.ts +++ b/packages/desktop/electron/main/contract.ts @@ -7,6 +7,9 @@ process.env.DIST = path.join(process.env.DIST_ELECTRON, '../dist'); export const url = import.meta.env.VITE_DEV_SERVER_URL; export const WEB_URL = import.meta.env.VITE_WEB_URL; export const VITE_API_URL = import.meta.env.VITE_API_URL; +// export const url = 'http://127.0.0.1:7777/'; +// export const WEB_URL = 'http://127.0.0.1:9191/'; +// export const VITE_API_URL = 'http://127.0.0.1:9190/'; export const preload = path.join(__dirname, '../preload/index.js'); export const DIST_ELECTRON = path.join(__dirname, '../'); diff --git a/packages/desktop/electron/main/index.ts b/packages/desktop/electron/main/index.ts index d9aef56e..9d3794fc 100644 --- a/packages/desktop/electron/main/index.ts +++ b/packages/desktop/electron/main/index.ts @@ -2,15 +2,14 @@ import { app, BrowserWindow, shell, ipcMain } from 'electron'; import { release } from 'node:os'; import * as mainWin from '../win/mainWin'; import { initTray } from './tray'; -import './ipcMain'; import { update } from './update'; import { registerFileProtocol } from './protocol'; import { registerGlobalShortcut, unregisterAllGlobalShortcut } from './globalShortcut'; -import { initConfig } from './config'; -import initApp from '@pear-rec/server/src'; +import { initConfig, getConfig } from '@pear-rec/server/src/config'; +import './ipcMain'; +import '@pear-rec/server/src'; -initApp(); -const config = initConfig(); +initConfig(); // The built directory structure // @@ -44,11 +43,11 @@ async function createWindow() { } app.whenReady().then(() => { + const config = getConfig(); registerFileProtocol(); createWindow(); initTray(config.language); registerGlobalShortcut(); - // Apply electron-updater update(); }); diff --git a/packages/desktop/electron/main/ipcMain.ts b/packages/desktop/electron/main/ipcMain.ts index 01a21c2f..eef4b371 100644 --- a/packages/desktop/electron/main/ipcMain.ts +++ b/packages/desktop/electron/main/ipcMain.ts @@ -14,7 +14,7 @@ import * as recordsWin from '../win/recordsWin'; import * as pinImageWin from '../win/pinImageWin'; import * as recorderFullScreenWin from '../win/recorderFullScreenWin'; import * as utils from './utils'; -import { editConfig } from './config'; +import { editConfig } from '@pear-rec/server/src/config'; const selfWindws = async () => await Promise.all( @@ -159,6 +159,9 @@ function initIpcMain() { ipcMain.handle('ss:get-desktop-capturer-source', async () => { return [...(await desktopCapturer.getSources({ types: ['screen'] })), ...(await selfWindws())]; }); + ipcMain.on('ss:copy-img', (e, imgUrl) => { + shotScreenWin.copyImg(imgUrl); + }); // 图片展示 ipcMain.on('vi:open-win', (e, search) => { viewImageWin.openViewImageWin(search); diff --git a/packages/desktop/electron/preload/electronAPI.ts b/packages/desktop/electron/preload/electronAPI.ts index f05c006e..9991e0c9 100644 --- a/packages/desktop/electron/preload/electronAPI.ts +++ b/packages/desktop/electron/preload/electronAPI.ts @@ -59,6 +59,7 @@ contextBridge.exposeInMainWorld('electronAPI', { sendSsDownloadImg: (imgUrl: string) => ipcRenderer.send('ss:download-img', imgUrl), sendSsSaveImg: (imgUrl: string) => ipcRenderer.send('ss:save-img', imgUrl), sendSsOpenExternal: (tabUrl: string) => ipcRenderer.send('ss:open-external', tabUrl), + sendSsCopyImg: (imgUrl: string) => ipcRenderer.send('ss:copy-img', imgUrl), //viWin sendViCloseWin: () => ipcRenderer.send('vi:close-win'), diff --git a/packages/desktop/electron/win/pinImageWin.ts b/packages/desktop/electron/win/pinImageWin.ts index a85f16d6..67230999 100644 --- a/packages/desktop/electron/win/pinImageWin.ts +++ b/packages/desktop/electron/win/pinImageWin.ts @@ -42,9 +42,7 @@ function closePinImageWin() { } function openPinImageWin(search?: any) { - if (!pinImageWin || pinImageWin?.isDestroyed()) { - pinImageWin = createPinImageWin(search); - } + pinImageWin = createPinImageWin(search); pinImageWin?.show(); } diff --git a/packages/desktop/electron/win/shotScreenWin.ts b/packages/desktop/electron/win/shotScreenWin.ts index 33713860..52cdd905 100644 --- a/packages/desktop/electron/win/shotScreenWin.ts +++ b/packages/desktop/electron/win/shotScreenWin.ts @@ -137,4 +137,5 @@ export { maximizeShotScreenWin, unmaximizeShotScreenWin, downloadURLShotScreenWin, + copyImg, }; diff --git a/packages/desktop/package.json b/packages/desktop/package.json index f727825e..4e2ee113 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -43,4 +43,4 @@ "engines": { "node": "^14.18.0 || >=16.0.0" } -} +} \ No newline at end of file diff --git a/packages/screenshot/src/Screenshots/icons/iconfont.scss b/packages/screenshot/src/Screenshots/icons/iconfont.scss index 3b5003b9..4c353741 100644 --- a/packages/screenshot/src/Screenshots/icons/iconfont.scss +++ b/packages/screenshot/src/Screenshots/icons/iconfont.scss @@ -1,78 +1,88 @@ @font-face { - font-family: "screenshots-icon"; /* Project id 572327 */ - src: url("iconfont.woff2") format("woff2"), - url("iconfont.woff") format("woff"), url("iconfont.ttf") format("truetype"); + font-family: 'screenshots-icon'; /* Project id 572327 */ + src: url('iconfont.woff2') format('woff2'), url('iconfont.woff') format('woff'), + url('iconfont.ttf') format('truetype'); } -[class^="icon-"], -[class*=" icon-"] { - font-family: "screenshots-icon" !important; - font-style: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; +[class^='icon-'], +[class*=' icon-'] { + font-family: 'screenshots-icon' !important; + font-style: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } .icon-ok:before { - content: "\e001"; + content: '\e001'; } .icon-cancel:before { - content: "\e002"; + content: '\e002'; } .icon-save:before { - content: "\e003"; + content: '\e003'; } .icon-redo:before { - content: "\e004"; + content: '\e004'; } .icon-undo:before { - content: "\e005"; + content: '\e005'; } .icon-mosaic:before { - content: "\e006"; + content: '\e006'; } .icon-text:before { - content: "\e007"; + content: '\e007'; } .icon-brush:before { - content: "\e008"; + content: '\e008'; } .icon-arrow:before { - content: "\e009"; + content: '\e009'; } .icon-ellipse:before { - content: "\e00a"; + content: '\e00a'; } .icon-rectangle:before { - content: "\e00b"; + content: '\e00b'; } .icon-scan:before { - content: ""; - background: transparent url(/imgs/svg/scan.svg) no-repeat 0px 0px; - background-size: 22px; - background-position: center; - width: 35px; - height: 35px; - display: inline-block; + content: ''; + background: transparent url(/imgs/svg/scan.svg) no-repeat 0px 0px; + background-size: 22px; + background-position: center; + width: 35px; + height: 35px; + display: inline-block; } .icon-search:before { - content: ""; - background: transparent url(/imgs/svg/search.svg) no-repeat 0px 0px; - background-size: 22px; - background-position: center; - width: 35px; - height: 35px; - display: inline-block; + content: ''; + background: transparent url(/imgs/svg/search.svg) no-repeat 0px 0px; + background-size: 22px; + background-position: center; + width: 35px; + height: 35px; + display: inline-block; +} + +.icon-pin:before { + content: ''; + background: transparent url(/imgs/svg/pin.svg) no-repeat 0px 0px; + background-size: 22px; + background-position: center; + width: 35px; + height: 35px; + display: inline-block; } diff --git a/packages/screenshot/src/Screenshots/operations/Pin/index.tsx b/packages/screenshot/src/Screenshots/operations/Pin/index.tsx new file mode 100644 index 00000000..50b6e0e1 --- /dev/null +++ b/packages/screenshot/src/Screenshots/operations/Pin/index.tsx @@ -0,0 +1,37 @@ +import React, { ReactElement, useCallback } from 'react'; +import useStore from '../../hooks/useStore'; +import useCall from '../../hooks/useCall'; +import useCanvasContextRef from '../../hooks/useCanvasContextRef'; +import useHistory from '../../hooks/useHistory'; +import useReset from '../../hooks/useReset'; +import ScreenshotsButton from '../../ScreenshotsButton'; +import composeImage from '../../composeImage'; + +export default function Pin(): ReactElement { + const { image, width, height, history, bounds, lang } = useStore(); + const canvasContextRef = useCanvasContextRef(); + const [, historyDispatcher] = useHistory(); + const call = useCall(); + const reset = useReset(); + + const onClick = useCallback(() => { + historyDispatcher.clearSelect(); + setTimeout(() => { + if (!canvasContextRef.current || !image || !bounds) { + return; + } + composeImage({ + image, + width, + height, + history, + bounds, + }).then((blob) => { + call('onPin', blob, bounds); + reset(); + }); + }); + }, [canvasContextRef, historyDispatcher, image, width, height, history, bounds, call, reset]); + + return ; +} diff --git a/packages/screenshot/src/Screenshots/operations/Scan/index.tsx b/packages/screenshot/src/Screenshots/operations/Scan/index.tsx index 4dfb0f5f..164f4419 100644 --- a/packages/screenshot/src/Screenshots/operations/Scan/index.tsx +++ b/packages/screenshot/src/Screenshots/operations/Scan/index.tsx @@ -1,62 +1,46 @@ -import React, { ReactElement, useCallback } from "react"; -import QrScanner from "qr-scanner"; -import useStore from "../../hooks/useStore"; -import useCall from "../../hooks/useCall"; -import useCanvasContextRef from "../../hooks/useCanvasContextRef"; -import useHistory from "../../hooks/useHistory"; -import useReset from "../../hooks/useReset"; -import ScreenshotsButton from "../../ScreenshotsButton"; -import composeImage from "../../composeImage"; +import React, { ReactElement, useCallback } from 'react'; +import QrScanner from 'qr-scanner'; +import useStore from '../../hooks/useStore'; +import useCall from '../../hooks/useCall'; +import useCanvasContextRef from '../../hooks/useCanvasContextRef'; +import useHistory from '../../hooks/useHistory'; +import useReset from '../../hooks/useReset'; +import ScreenshotsButton from '../../ScreenshotsButton'; +import composeImage from '../../composeImage'; -export default function Ok(): ReactElement { - const { image, width, height, history, bounds, lang } = useStore(); - const canvasContextRef = useCanvasContextRef(); - const [, historyDispatcher] = useHistory(); - const call = useCall(); - const reset = useReset(); +export default function Scan(): ReactElement { + const { image, width, height, history, bounds, lang } = useStore(); + const canvasContextRef = useCanvasContextRef(); + const [, historyDispatcher] = useHistory(); + const call = useCall(); + const reset = useReset(); - const onClick = useCallback(() => { - historyDispatcher.clearSelect(); - setTimeout(() => { - if (!canvasContextRef.current || !image || !bounds) { - return; - } - composeImage({ - image, - width, - height, - history, - bounds, - }).then(async (blob) => { - try { - const result = await QrScanner.scanImage(blob); - if (result) { - call("onScan", result); - } - } catch (error) { - console.error("Error:", error); - } + const onClick = useCallback(() => { + historyDispatcher.clearSelect(); + setTimeout(() => { + if (!canvasContextRef.current || !image || !bounds) { + return; + } + composeImage({ + image, + width, + height, + history, + bounds, + }).then(async (blob) => { + try { + const result = await QrScanner.scanImage(blob); + if (result) { + call('onScan', result); + } + } catch (error) { + console.error('Error:', error); + } - reset(); - }); - }); - }, [ - canvasContextRef, - historyDispatcher, - image, - width, - height, - history, - bounds, - call, - reset, - ]); + reset(); + }); + }); + }, [canvasContextRef, historyDispatcher, image, width, height, history, bounds, call, reset]); - return ( - - ); + return ; } diff --git a/packages/screenshot/src/Screenshots/operations/Search/index.tsx b/packages/screenshot/src/Screenshots/operations/Search/index.tsx index 160eb52b..5be43a3c 100644 --- a/packages/screenshot/src/Screenshots/operations/Search/index.tsx +++ b/packages/screenshot/src/Screenshots/operations/Search/index.tsx @@ -1,53 +1,39 @@ -import React, { ReactElement, useCallback } from "react"; -import useStore from "../../hooks/useStore"; -import useCall from "../../hooks/useCall"; -import useCanvasContextRef from "../../hooks/useCanvasContextRef"; -import useHistory from "../../hooks/useHistory"; -import useReset from "../../hooks/useReset"; -import ScreenshotsButton from "../../ScreenshotsButton"; -import composeImage from "../../composeImage"; +import React, { ReactElement, useCallback } from 'react'; +import useStore from '../../hooks/useStore'; +import useCall from '../../hooks/useCall'; +import useCanvasContextRef from '../../hooks/useCanvasContextRef'; +import useHistory from '../../hooks/useHistory'; +import useReset from '../../hooks/useReset'; +import ScreenshotsButton from '../../ScreenshotsButton'; +import composeImage from '../../composeImage'; -export default function Ok(): ReactElement { - const { image, width, height, history, bounds, lang } = useStore(); - const canvasContextRef = useCanvasContextRef(); - const [, historyDispatcher] = useHistory(); - const call = useCall(); - const reset = useReset(); +export default function Search(): ReactElement { + const { image, width, height, history, bounds, lang } = useStore(); + const canvasContextRef = useCanvasContextRef(); + const [, historyDispatcher] = useHistory(); + const call = useCall(); + const reset = useReset(); - const onClick = useCallback(() => { - historyDispatcher.clearSelect(); - setTimeout(() => { - if (!canvasContextRef.current || !image || !bounds) { - return; - } - composeImage({ - image, - width, - height, - history, - bounds, - }).then((blob) => { - call("onSearch", blob); - reset(); - }); - }); - }, [ - canvasContextRef, - historyDispatcher, - image, - width, - height, - history, - bounds, - call, - reset, - ]); + const onClick = useCallback(() => { + historyDispatcher.clearSelect(); + setTimeout(() => { + if (!canvasContextRef.current || !image || !bounds) { + return; + } + composeImage({ + image, + width, + height, + history, + bounds, + }).then((blob) => { + call('onSearch', blob); + reset(); + }); + }); + }, [canvasContextRef, historyDispatcher, image, width, height, history, bounds, call, reset]); - return ( - - ); + return ( + + ); } diff --git a/packages/screenshot/src/Screenshots/operations/index.ts b/packages/screenshot/src/Screenshots/operations/index.ts index 753be650..dc2d8a48 100644 --- a/packages/screenshot/src/Screenshots/operations/index.ts +++ b/packages/screenshot/src/Screenshots/operations/index.ts @@ -1,32 +1,34 @@ -import Ok from "./Ok"; -import Cancel from "./Cancel"; -import Save from "./Save"; -import Redo from "./Redo"; -import Undo from "./Undo"; -import Mosaic from "./Mosaic"; -import Text from "./Text"; -import Brush from "./Brush"; -import Arrow from "./Arrow"; -import Ellipse from "./Ellipse"; -import Rectangle from "./Rectangle"; -import Search from "./Search"; -import Scan from "./Scan"; +import Ok from './Ok'; +import Cancel from './Cancel'; +import Save from './Save'; +import Redo from './Redo'; +import Undo from './Undo'; +import Mosaic from './Mosaic'; +import Text from './Text'; +import Brush from './Brush'; +import Arrow from './Arrow'; +import Ellipse from './Ellipse'; +import Rectangle from './Rectangle'; +import Search from './Search'; +import Scan from './Scan'; +import Pin from './Pin'; export default [ - Scan, - Search, - "|", - Rectangle, - Ellipse, - Arrow, - Brush, - Text, - Mosaic, - "|", - Undo, - Redo, - "|", - Save, - Cancel, - Ok, + Pin, + Scan, + Search, + '|', + Rectangle, + Ellipse, + Arrow, + Brush, + Text, + Mosaic, + '|', + Undo, + Redo, + '|', + Save, + Cancel, + Ok, ]; diff --git a/packages/screenshot/src/Screenshots/zh_CN.ts b/packages/screenshot/src/Screenshots/zh_CN.ts index e1c1b274..b2327901 100644 --- a/packages/screenshot/src/Screenshots/zh_CN.ts +++ b/packages/screenshot/src/Screenshots/zh_CN.ts @@ -1,35 +1,37 @@ export interface Lang { - magnifier_position_label: string; - operation_ok_title: string; - operation_cancel_title: string; - operation_save_title: string; - operation_redo_title: string; - operation_undo_title: string; - operation_mosaic_title: string; - operation_text_title: string; - operation_brush_title: string; - operation_arrow_title: string; - operation_ellipse_title: string; - operation_rectangle_title: string; - operation_search_title: string; - operation_scan_title: string; + magnifier_position_label: string; + operation_ok_title: string; + operation_cancel_title: string; + operation_save_title: string; + operation_redo_title: string; + operation_undo_title: string; + operation_mosaic_title: string; + operation_text_title: string; + operation_brush_title: string; + operation_arrow_title: string; + operation_ellipse_title: string; + operation_rectangle_title: string; + operation_search_title: string; + operation_scan_title: string; + operation_pin_title: string; } const zhCN: Lang = { - magnifier_position_label: "坐标", - operation_ok_title: "确定", - operation_cancel_title: "取消", - operation_save_title: "保存", - operation_redo_title: "重做", - operation_undo_title: "撤销", - operation_mosaic_title: "马赛克", - operation_text_title: "文本", - operation_brush_title: "画笔", - operation_arrow_title: "箭头", - operation_ellipse_title: "椭圆", - operation_rectangle_title: "矩形", - operation_search_title: "搜图", - operation_scan_title: "扫码", + magnifier_position_label: '坐标', + operation_ok_title: '确定', + operation_cancel_title: '取消', + operation_save_title: '保存', + operation_redo_title: '重做', + operation_undo_title: '撤销', + operation_mosaic_title: '马赛克', + operation_text_title: '文本', + operation_brush_title: '画笔', + operation_arrow_title: '箭头', + operation_ellipse_title: '椭圆', + operation_rectangle_title: '矩形', + operation_search_title: '搜图', + operation_scan_title: '扫码', + operation_pin_title: '钉图', }; export default zhCN; diff --git a/packages/server/index.d.ts b/packages/server/index.d.ts deleted file mode 100644 index 0499d1a1..00000000 --- a/packages/server/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export default function initApp(); diff --git a/packages/server/index.ts b/packages/server/index.ts deleted file mode 100644 index d45ec5bd..00000000 --- a/packages/server/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import initApp from './src'; - -initApp(); diff --git a/packages/server/package.json b/packages/server/package.json index ccf3d4a1..26ef4994 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -7,6 +7,7 @@ "scripts": { "dev": "nodemon index.ts", "build": "rollup -c", + "watch": "rollup -c --watch", "preview": "node dist/index.js" }, "author": "027xiguapi", @@ -35,4 +36,4 @@ "sql.js": "^1.8.0", "typeorm": "^0.3.17" } -} +} \ No newline at end of file diff --git a/packages/server/src/config/index.ts b/packages/server/src/config/index.ts index 525a540f..93785899 100644 --- a/packages/server/src/config/index.ts +++ b/packages/server/src/config/index.ts @@ -72,14 +72,18 @@ export function resetConfig() { } } -export function editConfig(key: string, value: any) { +export function editConfig(key: string, value: any, cb?: Function) { try { let config = jsonfile.readFileSync(CONFIG_FILE_PATH) || {}; config[key] = value; - jsonfile.writeFileSync(CONFIG_FILE_PATH, config, { - spaces: 2, - EOL: '\r\n', - }); + jsonfile + .writeFile(CONFIG_FILE_PATH, config, { + spaces: 2, + EOL: '\r\n', + }) + .then(() => { + cb && cb(); + }); return config; } catch (err) { console.log('editConfig :', err); diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 3180af01..f2778dbf 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -3,7 +3,7 @@ import cors from 'cors'; import bodyParser from 'body-parser'; import express, { Request, Response } from 'express'; import { AppDataSource } from './dataSource'; -import { AppRoutes } from './route'; +import { AppRoutes } from './route/index'; import { initApi } from './api'; import { initConfig } from './config'; import { PORT } from './contract'; @@ -39,3 +39,5 @@ export default function initApp() { }) .catch((error) => console.log('TypeORM connection error: ', error)); } + +initApp(); diff --git a/packages/server/src/route/index.ts b/packages/server/src/route/index.ts index 5ce73212..467cf24e 100644 --- a/packages/server/src/route/index.ts +++ b/packages/server/src/route/index.ts @@ -1,6 +1,6 @@ -import { UserRoutes } from "./User"; -import { RecordRoutes } from "./Record"; -import { SettingRoutes } from "./Setting"; +import { UserRoutes } from './User'; +import { RecordRoutes } from './Record'; +import { SettingRoutes } from './Setting'; /** * All application routes. diff --git a/packages/server/src/util/index.ts b/packages/server/src/util/index.ts index 37a34587..9601f811 100644 --- a/packages/server/src/util/index.ts +++ b/packages/server/src/util/index.ts @@ -22,6 +22,7 @@ export function getImgsByImgUrl(imgUrl: string, isElectron: boolean) { filePath == imgUrl && (currentIndex = index); imgs.push({ url: `${getProtocol(isElectron, 'getFile')}${filePath}`, + filePath: filePath, index, }); index++; diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index f857aa6a..e8ac29be 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ESNext", + "target": "ES5", "experimentalDecorators": true, "emitDecoratorMetadata": true, "esModuleInterop": true, diff --git a/packages/web/CHANGELOG.md b/packages/web/CHANGELOG.md index 139e5015..a3abdec4 100644 --- a/packages/web/CHANGELOG.md +++ b/packages/web/CHANGELOG.md @@ -1,5 +1,9 @@ # @pear-rec/web +## 1.3.5 + +feat: 截图钉图 + ## 1.3.4 feat: 重置设置、显示快捷键 diff --git a/packages/web/package.json b/packages/web/package.json index 9abeb8ec..5907ff04 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@pear-rec/web", "private": true, - "version": "1.3.2", + "version": "1.3.5", "scripts": { "dev": "vite", "build": "rimraf dist && tsc && vite build", diff --git a/packages/web/public/imgs/svg/pin.svg b/packages/web/public/imgs/svg/pin.svg new file mode 100644 index 00000000..edbfc6af --- /dev/null +++ b/packages/web/public/imgs/svg/pin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/web/src/components/card/editImageCard.tsx b/packages/web/src/components/card/editImageCard.tsx index 34ab7ed9..2f1656b8 100644 --- a/packages/web/src/components/card/editImageCard.tsx +++ b/packages/web/src/components/card/editImageCard.tsx @@ -10,7 +10,7 @@ const EditImageCard = forwardRef((props: any, ref: any) => { function handleUploadFile(event) { const file = event.target.files[0]; if (window.electronAPI) { - window.electronAPI.sendEiOpenWin({ imgUrl: 'pearrec:///' + file.path }); + window.electronAPI.sendEiOpenWin({ imgUrl: file.path }); } else { const imgUrl = window.URL.createObjectURL(file); Modal.confirm({ diff --git a/packages/web/src/pages/editImage/index.tsx b/packages/web/src/pages/editImage/index.tsx index 01447aeb..af06612d 100644 --- a/packages/web/src/pages/editImage/index.tsx +++ b/packages/web/src/pages/editImage/index.tsx @@ -190,6 +190,9 @@ const EditImage = () => { const paramsString = location.search; const searchParams = new URLSearchParams(paramsString); let imgUrl = searchParams.get('imgUrl'); + if (imgUrl.substring(0, 4) != 'blob') { + imgUrl = `${window.baseURL}getFile?url=${imgUrl}`; + } const instance = new ImageEditor(document.querySelector('#tui-image-editor'), { includeUI: { loadImage: { diff --git a/packages/web/src/pages/main.tsx b/packages/web/src/pages/main.tsx index 11c3b112..0b2e3f01 100644 --- a/packages/web/src/pages/main.tsx +++ b/packages/web/src/pages/main.tsx @@ -6,6 +6,7 @@ export default function initApp(App) { const userAgent = navigator.userAgent.toLowerCase(); window.isElectron = userAgent.indexOf(' electron/') > -1 ? true : false; window.isOffline = location.host == 'pear-rec-xiguapi.vercel.app' ? true : false; + window.baseURL = import.meta.env.VITE_API_URL; const container = document.getElementById('root') as HTMLElement; const root = createRoot(container); initI18n(); diff --git a/packages/web/src/pages/pinImage/index.tsx b/packages/web/src/pages/pinImage/index.tsx index a802637e..0fefd0e3 100644 --- a/packages/web/src/pages/pinImage/index.tsx +++ b/packages/web/src/pages/pinImage/index.tsx @@ -53,9 +53,14 @@ const PinImage: React.FC = () => { const paramsString = location.search; const searchParams = new URLSearchParams(paramsString); let _imgUrl = searchParams.get('imgUrl') || defaultImg; + if (_imgUrl.substring(0, 4) != 'blob') { + _imgUrl = `${window.baseURL}getFile?url=${_imgUrl}`; + } + fetch(_imgUrl) .then((response) => response.blob()) // 将获取到的图片转为 Blob .then((blob) => { + console.log(blob); setImgUrl(`url(${URL.createObjectURL(blob)})`); }); } diff --git a/packages/web/src/pages/shotScreen/index.tsx b/packages/web/src/pages/shotScreen/index.tsx index df2235ff..df98c904 100644 --- a/packages/web/src/pages/shotScreen/index.tsx +++ b/packages/web/src/pages/shotScreen/index.tsx @@ -114,7 +114,7 @@ function ShotScreen() { window.isOffline ? saveAs(url, `pear-rec_${+new Date()}.png`) : saveFile(blob); }, []); - async function saveFile(blob) { + async function saveFile(blob, isPin?) { try { const formData = new FormData(); formData.append('type', 'ss'); @@ -122,9 +122,14 @@ function ShotScreen() { formData.append('file', blob); const res = (await api.saveFile(formData)) as any; if (res.code == 0) { + copyImg(window.isElectron ? res.data.filePath : blob); if (window.isElectron) { window.electronAPI?.sendSsCloseWin(); - window.electronAPI?.sendViOpenWin({ imgUrl: res.data.filePath }); + isPin + ? window.electronAPI?.sendPiOpenWin({ + imgUrl: res.data.filePath, + }) + : window.electronAPI?.sendViOpenWin({ imgUrl: res.data.filePath }); } else { Modal.confirm({ title: '图片已保存,是否查看?', @@ -132,7 +137,9 @@ function ShotScreen() { okText: t('modal.ok'), cancelText: t('modal.cancel'), onOk() { - location.href = `/viewImage.html?imgUrl=${res.data.filePath}`; + location.href = isPin + ? `/pinImage.html?imgUrl=${res.data.filePath}` + : `/viewImage.html?imgUrl=${res.data.filePath}`; }, }); } @@ -142,15 +149,21 @@ function ShotScreen() { } } - async function copyImg(url) { - const data = await fetch(url); - const blob = await data.blob(); + const onPin = useCallback(async (blob) => { + const imgUrl = URL.createObjectURL(blob); + window.isOffline ? saveAs(imgUrl, `pear-rec_${+new Date()}.png`) : saveFile(blob, true); + }, []); - await navigator.clipboard.write([ - new ClipboardItem({ - [blob.type]: blob, - }), - ]); + async function copyImg(blob) { + if (window.isElectron) { + window.electronAPI.sendSsCopyImg(blob); + } else { + await navigator.clipboard.write([ + new ClipboardItem({ + [blob.type]: blob, + }), + ]); + } } function handleUploadImg(files) { @@ -170,6 +183,7 @@ function ShotScreen() { onOk={onOk} onSearch={onSearch} onScan={onScan} + onPin={onPin} /> ) : window.isElectron ? ( <> diff --git a/packages/web/src/pages/viewImage/index.tsx b/packages/web/src/pages/viewImage/index.tsx index 0f0c4868..9159c07a 100644 --- a/packages/web/src/pages/viewImage/index.tsx +++ b/packages/web/src/pages/viewImage/index.tsx @@ -20,11 +20,11 @@ const ViewImage = () => { const { t } = useTranslation(); const api = useApi(); const userApi = useUserApi(); - let viewerRef = useRef(); + const viewerRef = useRef(); + const initialViewIndexRef = useRef(0); const inputRef = useRef(null); const [user, setUser] = useState({}); const [imgs, setImgs] = useState([]); - const [initialViewIndex, setInitialViewIndex] = useState(0); const [isFull, setIsFull] = useState(false); useEffect(() => { @@ -62,7 +62,7 @@ const ViewImage = () => { // 3: width>992px // 4: width>1200px inline: true, - initialViewIndex: initialViewIndex, + initialViewIndex: initialViewIndexRef.current, className: 'viewImgs', toolbar: { alwaysOnTopWin: handleToggleAlwaysOnTopWin, @@ -71,7 +71,7 @@ const ViewImage = () => { }, scan: async () => { try { - const imgUrl = imgs[initialViewIndex]?.url; + const imgUrl = imgs[initialViewIndexRef.current]?.url; const result = await QrScanner.scanImage(imgUrl); Modal.confirm({ title: '扫码结果', @@ -94,7 +94,7 @@ const ViewImage = () => { } }, search: async () => { - const imgUrl = imgs[initialViewIndex]?.url; + const imgUrl = imgs[initialViewIndexRef.current]?.url; const blob = await urlToBlob(imgUrl); const tabUrl = await searchImg(blob, user.isProxy); if (window.electronAPI) { @@ -121,7 +121,7 @@ const ViewImage = () => { window.print(); }, edit: () => { - const imgUrl = imgs[initialViewIndex]?.url; + const imgUrl = imgs[initialViewIndexRef.current]?.filePath; if (window.electronAPI) { window.electronAPI.sendViCloseWin(); window.electronAPI.sendEiOpenWin({ imgUrl }); @@ -131,6 +131,9 @@ const ViewImage = () => { } }, }, + viewed: () => { + initialViewIndexRef.current = viewer.index; + }, }) as any; viewerRef.current = viewer; } @@ -201,15 +204,13 @@ const ViewImage = () => { } async function handleToggleAlwaysOnTopWin() { - const imgUrl = imgs[initialViewIndex]?.url; + const imgUrl = imgs[initialViewIndexRef.current]?.filePath; if (window.isElectron) { + window.electronAPI.sendViCloseWin(); window.electronAPI.sendPiOpenWin({ imgUrl }); } else { window.open(`/pinImage.html?imgUrl=${imgUrl}`); } - // const isAlwaysOnTop = await window.electronAPI?.invokeViSetIsAlwaysOnTop(); - // const icon = document.querySelector('.viewer-always-on-top-win'); - // isAlwaysOnTop ? icon.classList.add('current') : icon.classList.remove('current'); } async function initImgs() { @@ -218,18 +219,18 @@ const ViewImage = () => { const imgUrl = searchParams.get('imgUrl') || user.historyImg; if (imgUrl) { if (imgUrl.substring(0, 4) == 'blob') { - setImgs([{ url: imgUrl, index: 0 }]); + setImgs([{ url: imgUrl, filePath: imgUrl, index: 0 }]); } else { const res = (await api.getImgs(imgUrl)) as any; if (res.code == 0) { setImgs(res.data.imgs); - setInitialViewIndex(res.data.currentIndex); + initialViewIndexRef.current = res.data.currentIndex; } else { - setImgs([{ url: imgUrl, index: 0 }]); + setImgs([{ url: imgUrl, filePath: imgUrl, index: 0 }]); } } } else { - setImgs([{ url: defaultImg, index: 0 }]); + setImgs([{ url: defaultImg, filePath: defaultImg, index: 0 }]); } } @@ -238,7 +239,7 @@ const ViewImage = () => { const url = window.URL.createObjectURL(selectedFile); viewerRef.current?.destroy(); setImgs([...imgs, { url: url, index: imgs.length }]); - setInitialViewIndex(imgs.length); + initialViewIndexRef.current = imgs.length; } return ( diff --git a/packages/web/src/vite-env.d.ts b/packages/web/src/vite-env.d.ts index 87e5d24a..137706fe 100644 --- a/packages/web/src/vite-env.d.ts +++ b/packages/web/src/vite-env.d.ts @@ -3,17 +3,18 @@ export {}; declare global { - interface Window { - electronAPI: any; - isElectron: boolean; + interface Window { + electronAPI: any; + isElectron: boolean; isOffline: boolean; - } + baseURL: string; + } } -declare module "react" { - interface InputHTMLAttributes extends HTMLAttributes { - // extends React's HTMLAttributes - directory?: string; - webkitdirectory?: string; - } +declare module 'react' { + interface InputHTMLAttributes extends HTMLAttributes { + // extends React's HTMLAttributes + directory?: string; + webkitdirectory?: string; + } }