Browse Source

Merge branch 'master' of https://gitee.com/godoos/godoos

master
godo 6 months ago
parent
commit
4253f185a1
  1. 11
      frontend/components.d.ts
  2. 2
      frontend/package.json
  3. 31
      frontend/pnpm-lock.yaml
  4. 0
      frontend/public/image/login/sina.png
  5. 0
      frontend/public/image/login/wechat.png
  6. BIN
      frontend/src/assets/login/GitHub.png
  7. BIN
      frontend/src/assets/login/QQ.png
  8. BIN
      frontend/src/assets/login/gitee.png
  9. BIN
      frontend/src/assets/login/sina.png
  10. BIN
      frontend/src/assets/login/wechat.png
  11. 22
      frontend/src/components/computer/Computer.vue
  12. 97
      frontend/src/components/desktop/LockDesktop.vue
  13. 154
      frontend/src/components/setting/SetLang.vue
  14. 12
      frontend/src/components/ui/WinUpButtonGroup.vue
  15. 18
      frontend/src/components/window/IframeFile.vue
  16. 10
      frontend/src/components/window/MenuFooter.vue
  17. 2
      frontend/src/components/window/WindowInner.vue
  18. 10
      frontend/src/components/window/WindowTemplate.vue
  19. 67
      frontend/src/stores/choose.ts
  20. 10
      frontend/src/system/window/Dialog.ts

11
frontend/components.d.ts

@ -67,18 +67,26 @@ declare module 'vue' {
ElCard: typeof import('element-plus/es')['ElCard'] ElCard: typeof import('element-plus/es')['ElCard']
ElCarousel: typeof import('element-plus/es')['ElCarousel'] ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem'] ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol'] ElCol: typeof import('element-plus/es')['ElCol']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElContainer: typeof import('element-plus/es')['ElContainer'] ElContainer: typeof import('element-plus/es')['ElContainer']
ElDialog: typeof import('element-plus/es')['ElDialog'] ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty'] ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElFooter: typeof import('element-plus/es')['ElFooter']
ElForm: typeof import('element-plus/es')['ElForm'] ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader'] ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon'] ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage'] ElImage: typeof import('element-plus/es')['ElImage']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader'] ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: typeof import('element-plus/es')['ElPagination']
@ -97,6 +105,8 @@ declare module 'vue' {
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElText: typeof import('element-plus/es')['ElText'] ElText: typeof import('element-plus/es')['ElText']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTransfer: typeof import('element-plus/es')['ElTransfer']
ElTree: typeof import('element-plus/es')['ElTree']
Error: typeof import('./src/components/taskbar/Error.vue')['default'] Error: typeof import('./src/components/taskbar/Error.vue')['default']
FileIcon: typeof import('./src/components/builtin/FileIcon.vue')['default'] FileIcon: typeof import('./src/components/builtin/FileIcon.vue')['default']
FileIconImg: typeof import('./src/components/builtin/FileIconImg.vue')['default'] FileIconImg: typeof import('./src/components/builtin/FileIconImg.vue')['default']
@ -106,7 +116,6 @@ declare module 'vue' {
FilePwd: typeof import('./src/components/oa/FilePwd.vue')['default'] FilePwd: typeof import('./src/components/oa/FilePwd.vue')['default']
FileTree: typeof import('./src/components/builtin/FileTree.vue')['default'] FileTree: typeof import('./src/components/builtin/FileTree.vue')['default']
FileViewer: typeof import('./src/components/builtin/FileViewer.vue')['default'] FileViewer: typeof import('./src/components/builtin/FileViewer.vue')['default']
GithubNext: typeof import('./src/components/desktop/GithubNext.vue')['default']
IframeFile: typeof import('./src/components/window/IframeFile.vue')['default'] IframeFile: typeof import('./src/components/window/IframeFile.vue')['default']
ImageViewer: typeof import('./src/components/builtin/ImageViewer.vue')['default'] ImageViewer: typeof import('./src/components/builtin/ImageViewer.vue')['default']
Install: typeof import('./src/components/install/Install.vue')['default'] Install: typeof import('./src/components/install/Install.vue')['default']

2
frontend/package.json

@ -19,6 +19,7 @@
"jszip": "^3.10.1", "jszip": "^3.10.1",
"lunar-typescript": "^1.7.6", "lunar-typescript": "^1.7.6",
"moment": "^2.30.1", "moment": "^2.30.1",
"nanoid": "^5.0.9",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"pinia-plugin-persist": "^1.0.0", "pinia-plugin-persist": "^1.0.0",
"vite-plugin-svg-icons": "^2.0.1", "vite-plugin-svg-icons": "^2.0.1",
@ -31,6 +32,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/file-saver": "^2.0.7", "@types/file-saver": "^2.0.7",
"@types/nanoid": "^3.0.0",
"@types/node": "^20.14.10", "@types/node": "^20.14.10",
"@vitejs/plugin-vue": "^5.0.5", "@vitejs/plugin-vue": "^5.0.5",
"sass": "^1.77.8", "sass": "^1.77.8",

31
frontend/pnpm-lock.yaml

@ -33,11 +33,14 @@ importers:
specifier: ^3.10.1 specifier: ^3.10.1
version: 3.10.1 version: 3.10.1
lunar-typescript: lunar-typescript:
specifier: ^1.7.5 specifier: ^1.7.6
version: 1.7.5 version: 1.7.6
moment: moment:
specifier: ^2.30.1 specifier: ^2.30.1
version: 2.30.1 version: 2.30.1
nanoid:
specifier: ^5.0.9
version: 5.0.9
pinia: pinia:
specifier: ^2.1.7 specifier: ^2.1.7
version: 2.2.4(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3)) version: 2.2.4(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3))
@ -69,6 +72,9 @@ importers:
'@types/file-saver': '@types/file-saver':
specifier: ^2.0.7 specifier: ^2.0.7
version: 2.0.7 version: 2.0.7
'@types/nanoid':
specifier: ^3.0.0
version: 3.0.0
'@types/node': '@types/node':
specifier: ^20.14.10 specifier: ^20.14.10
version: 20.16.13 version: 20.16.13
@ -534,6 +540,10 @@ packages:
'@types/lodash@4.17.12': '@types/lodash@4.17.12':
resolution: {integrity: sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==} resolution: {integrity: sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==}
'@types/nanoid@3.0.0':
resolution: {integrity: sha512-UXitWSmXCwhDmAKe7D3hNQtQaHeHt5L8LO1CB8GF8jlYVzOv5cBWDNqiJ+oPEWrWei3i3dkZtHY/bUtd0R/uOQ==}
deprecated: This is a stub types definition. nanoid provides its own type definitions, so you do not need this installed.
'@types/node@20.16.13': '@types/node@20.16.13':
resolution: {integrity: sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==} resolution: {integrity: sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==}
@ -2040,8 +2050,8 @@ packages:
lottie-web@5.12.2: lottie-web@5.12.2:
resolution: {integrity: sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==} resolution: {integrity: sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==}
lunar-typescript@1.7.5: lunar-typescript@1.7.6:
resolution: {integrity: sha512-AlOwYrxHRCR9Plba5TlZY0NVv6aFobmR1gxfiAE1KxjDzBXoDtT2KrsBYCVaErGokiL8qLMS1FNwGPiPRX2a4g==} resolution: {integrity: sha512-vrNRgzJ6UgK++P81jaOykV7YBCLemC8l/XDbsXE7MinojXolOKiIHm6sOZg5wdDMbJxCWP1ERAaqcBV9mhw2Bg==}
magic-string@0.30.12: magic-string@0.30.12:
resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==}
@ -2145,6 +2155,11 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
nanoid@5.0.9:
resolution: {integrity: sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==}
engines: {node: ^18 || >=20}
hasBin: true
nanomatch@1.2.13: nanomatch@1.2.13:
resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@ -3356,6 +3371,10 @@ snapshots:
'@types/lodash@4.17.12': {} '@types/lodash@4.17.12': {}
'@types/nanoid@3.0.0':
dependencies:
nanoid: 5.0.9
'@types/node@20.16.13': '@types/node@20.16.13':
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.19.8
@ -5330,7 +5349,7 @@ snapshots:
lottie-web@5.12.2: {} lottie-web@5.12.2: {}
lunar-typescript@1.7.5: {} lunar-typescript@1.7.6: {}
magic-string@0.30.12: magic-string@0.30.12:
dependencies: dependencies:
@ -5481,6 +5500,8 @@ snapshots:
nanoid@3.3.7: {} nanoid@3.3.7: {}
nanoid@5.0.9: {}
nanomatch@1.2.13(supports-color@3.2.3): nanomatch@1.2.13(supports-color@3.2.3):
dependencies: dependencies:
arr-diff: 4.0.0 arr-diff: 4.0.0

0
frontend/public/image/login/新浪微博.png → frontend/public/image/login/sina.png

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

0
frontend/public/image/login/微信.png → frontend/public/image/login/wechat.png

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
frontend/src/assets/login/GitHub.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
frontend/src/assets/login/QQ.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
frontend/src/assets/login/gitee.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
frontend/src/assets/login/sina.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
frontend/src/assets/login/wechat.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

22
frontend/src/components/computer/Computer.vue

@ -154,6 +154,8 @@
turnLocalPath, turnLocalPath,
} from "@/util/sharePath.ts"; } from "@/util/sharePath.ts";
import { useChooseStore } from "@/stores/choose";
const { choseStart, chosing, choseEnd, getRect, Chosen } = useRectChosen(); const { choseStart, chosing, choseEnd, getRect, Chosen } = useRectChosen();
const browserWindow: BrowserWindow | undefined = inject("browserWindow"); const browserWindow: BrowserWindow | undefined = inject("browserWindow");
@ -171,11 +173,15 @@
const props = defineProps({ const props = defineProps({
translateSavePath: { translateSavePath: {
type: Function type: Function
},
componentID:{
} }
}) })
const setRouter = function (path: string) { const setRouter = function (path: string) {
if (props.translateSavePath) { if (props.translateSavePath && props.componentID) {
props.translateSavePath(path) props.translateSavePath(path)
// router_url_history.value.push(path);
} }
router_url.value = path; router_url.value = path;
if ( if (
@ -190,6 +196,8 @@
router_url_history_index.value = router_url_history.value.length; router_url_history_index.value = router_url_history.value.length;
router_url_history.value.push(path); router_url_history.value.push(path);
}; };
const choose = useChooseStore()
const { refersh, createFolder, backFolder, openFolder, onComputerMount } = const { refersh, createFolder, backFolder, openFolder, onComputerMount } =
useComputer({ useComputer({
setRouter: setRouter, setRouter: setRouter,
@ -355,6 +363,18 @@
shareShow.value = shareShow.value =
system.getConfig("userType") === "member" ? true : false; system.getConfig("userType") === "member" ? true : false;
// console.log('', system.getConfig('userInfo').id); // console.log('', system.getConfig('userInfo').id);
//
if (props.translateSavePath && choose.saveFileContent.length > 0) {
// setRouter(choose.saveFileContent.defaultPath)
let pos = -1
choose.saveFileContent.forEach((item, index) => {
if (item.componentID == props.componentID) {
pos = index
}
})
if (pos !== -1) onTreeOpen(choose.saveFileContent[pos].defaultPath)
// console.log('',pos, choose.saveFileContent);
}
}); });
function handleOuterClick() { function handleOuterClick() {

97
frontend/src/components/desktop/LockDesktop.vue

@ -48,54 +48,17 @@
</div> </div>
<div class="third-party-login"> <div class="third-party-login">
<img <img
v-for="platform in thirdPartyPlatforms"
:key="platform.name"
:src="platform.icon"
:alt="platform.name"
style=" style="
width: 25px; width: 25px;
height: 25px; height: 25px;
cursor: pointer; cursor: pointer;
color: #409eff; color: #409eff;
" "
src="../../../public/image/login/微信.png" @click="onThirdPartyLogin(platform.name)"
@click="onThirdPartyLogin('wechat')"
/>
<img
style="
width: 25px;
height: 25px;
cursor: pointer;
color: #409eff;
"
src="../../../public/image/login/QQ.png"
@click="onThirdPartyLogin('qq')"
/>
<img
style="
width: 25px;
height: 25px;
cursor: pointer;
color: #409eff;
"
src="../../../public/image/login/新浪微博.png"
@click="onThirdPartyLogin('sina')"
/>
<img
style="
width: 25px;
height: 25px;
cursor: pointer;
color: #409eff;
"
src="../../../public/image/login/GitHub.png"
@click="onThirdPartyLogin('github')"
/>
<img
style="
width: 25px;
height: 25px;
cursor: pointer;
color: #409eff;
"
src="../../../public/image/login/gitee.png"
@click="onThirdPartyLogin('gitee')"
/> />
</div> </div>
<div <div
@ -199,6 +162,30 @@
const config = getSystemConfig(); const config = getSystemConfig();
const lockClassName = ref("screen-show"); const lockClassName = ref("screen-show");
const isRegisterMode = ref(false); const isRegisterMode = ref(false);
const thirdPartyPlatforms = [
{
name: "wechat",
icon: new URL("@/assets/login/wechat.png", import.meta.url).href,
},
{
name: "qq",
icon: new URL("@/assets/login/qq.png", import.meta.url).href,
},
{
name: "sina",
icon: new URL("@/assets/login/sina.png", import.meta.url).href,
},
{
name: "github",
icon: new URL("@/assets/login/github.png", import.meta.url).href,
},
{
name: "gitee",
icon: new URL("@/assets/login/gitee.png", import.meta.url).href,
},
];
function loginSuccess() { function loginSuccess() {
lockClassName.value = "screen-hidean"; lockClassName.value = "screen-hidean";
setTimeout(() => { setTimeout(() => {
@ -219,6 +206,7 @@
} }
}); });
// code
watch( watch(
() => router.currentRoute.value.query.code, () => router.currentRoute.value.query.code,
() => { () => {
@ -249,6 +237,8 @@
const returnedState = router.currentRoute.value.query const returnedState = router.currentRoute.value.query
.state as string; .state as string;
console.log(returnedState, "---", store.State);
if (returnedState !== store.State) { if (returnedState !== store.State) {
notifyError("登录失败,请重试"); notifyError("登录失败,请重试");
return; return;
@ -402,7 +392,7 @@
break; break;
case "gitee": case "gitee":
loginFunction = async function () { loginFunction = async function () {
return await authWithGithub(); return await authWithGitee();
}; };
break; break;
default: default:
@ -423,7 +413,6 @@
const authWithGithub = async (): Promise<boolean> => { const authWithGithub = async (): Promise<boolean> => {
// stateCSRF,使 // stateCSRF,使
const state = Date.now() + Math.random().toString(36).substring(2, 15); const state = Date.now() + Math.random().toString(36).substring(2, 15);
//
store.State = state; store.State = state;
const url = config.userInfo.url + "/github/authorize?state=" + state; const url = config.userInfo.url + "/github/authorize?state=" + state;
const res: any = await fetch(url, { const res: any = await fetch(url, {
@ -452,6 +441,26 @@
const authWithSina = (): boolean | PromiseLike<boolean> => { const authWithSina = (): boolean | PromiseLike<boolean> => {
throw new Error("Function not implemented."); throw new Error("Function not implemented.");
}; };
const authWithGitee = async (): Promise<boolean> => {
// stateCSRF,使
const state = Date.now() + Math.random().toString(36).substring(2, 15);
store.State = state;
const url = config.userInfo.url + "/gitee/authorize?state=" + state;
const res: any = await fetch(url, {
method: "POST",
body: JSON.stringify({
state: state,
}),
});
if (!res.ok) {
return false;
}
const data = await res.json();
// Gitee
window.location.href = data.data.url;
return true;
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

154
frontend/src/components/setting/SetLang.vue

@ -1,88 +1,90 @@
<template> <template>
<div class="container"> <div class="container">
<div class="nav"> <div class="nav">
<ul> <ul>
<li <li
v-for="(item, index) in items" v-for="(item, index) in items"
:key="index" :key="index"
@click="selectItem(index)" @click="selectItem(index)"
:class="{ active: index === activeIndex }" :class="{ active: index === activeIndex }"
> >
{{ item }} {{ item }}
</li> </li>
</ul> </ul>
</div> </div>
<div class="setting"> <div class="setting">
<div v-if="0 === activeIndex"> <div v-if="0 === activeIndex">
<div class="setting-item"> <div class="setting-item">
<h1 class="setting-title">{{ t("language") }}</h1> <h1 class="setting-title">{{ t("language") }}</h1>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label></label> <label></label>
<el-select v-model="modelvalue"> <el-select v-model="modelvalue">
<el-option <el-option
v-for="(item, key) in langList" v-for="(item, key) in langList"
:key="key" :key="key"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
/> />
</el-select> </el-select>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label></label> <label></label>
<el-button @click="submit" type="primary"> <el-button
{{ t("confirm") }} @click="submit"
</el-button> type="primary"
</div> >
</div> {{ t("confirm") }}
</div> </el-button>
</div> </div>
</div>
</div>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { getLang, setLang, t } from "@/i18n";
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from "element-plus";
import { t, getLang, setLang } from "@/i18n"; import { ref } from "vue";
import { useI18n } from 'vue-i18n'; import { useI18n } from "vue-i18n";
const { locale } = useI18n() const { locale } = useI18n();
const showDialog = ref(false); // const showDialog = ref(false);
const langList = [ const langList = [
{ {
label: "中文", label: "中文",
value: "zh-cn", value: "zh-cn",
}, },
{ {
label: "English", label: "English",
value: "en", value: "en",
}, },
]; ];
const items = [t("language")]; const items = [t("language")];
const activeIndex = ref(0); const activeIndex = ref(0);
const currentLang = getLang(); const currentLang = getLang();
const modelvalue = ref(currentLang); const modelvalue = ref(currentLang);
const selectItem = (index: number) => { const selectItem = (index: number) => {
activeIndex.value = index; activeIndex.value = index;
}; };
async function submit() { async function submit() {
setLang(modelvalue.value); setLang(modelvalue.value);
locale.value = modelvalue.value; locale.value = modelvalue.value;
ElMessageBox.alert(t("save.success"), t("language"), { ElMessageBox.alert(t("save.success"), t("language"), {
confirmButtonText: 'OK', confirmButtonText: "OK",
}) });
//showDialog.value = false //showDialog.value = false
// Dialog.showMessageBox({ // Dialog.showMessageBox({
// message: t("save.success"), // message: t("save.success"),
// title: t("language"), // title: t("language"),
// type: "info", // type: "info",
// }); // });
} }
</script> </script>
<style scoped> <style scoped>
@import "./setStyle.css"; @import "./setStyle.css";
</style> </style>

12
frontend/src/components/ui/WinUpButtonGroup.vue

@ -40,10 +40,17 @@
<script lang="ts" setup> <script lang="ts" setup>
import { BrowserWindow, WindowStateEnum } from '@/system/window/BrowserWindow'; import { BrowserWindow, WindowStateEnum } from '@/system/window/BrowserWindow';
import { UnwrapNestedRefs } from 'vue'; import { UnwrapNestedRefs } from 'vue';
import { useChooseStore } from "@/stores/choose";
const choose = useChooseStore()
const props = defineProps<{ const props = defineProps<{
browserWindow: UnwrapNestedRefs<BrowserWindow>; browserWindow: UnwrapNestedRefs<BrowserWindow>;
}>(); }>();
const close = () => {
if(choose.isExist(props.browserWindow.windowInfo.componentID)) {
choose.closeSaveFile(props.browserWindow.windowInfo.componentID)
}
props.browserWindow.destroy();
}
function handleEvent(event: string) { function handleEvent(event: string) {
switch (event) { switch (event) {
case 'min': case 'min':
@ -59,7 +66,8 @@ function handleEvent(event: string) {
} }
break; break;
case 'close': case 'close':
props.browserWindow.destroy(); close();
// props.browserWindow.destroy();
break; break;
} }
} }

18
frontend/src/components/window/IframeFile.vue

@ -46,15 +46,16 @@ const saveFile = async (e: any) => {
if (data.ext) { if (data.ext) {
ext = data.ext; ext = data.ext;
} }
const fileName = e.fileName == '' ? data.title : e.fileName
let path:string let path:string
e.filePath !== "" e.filePath !== ""
? (path = `${e.filePath}/${e.fileName}.${ext}`) ? (path = `${e.filePath}/${fileName}.${ext}`)
: (path = `${SP}C${SP}Users${SP}Desktop${SP}${e.fileName}.${ext}`); : (path = `${SP}C${SP}Users${SP}Desktop${SP}${fileName}.${ext}`);
// console.log('',path); // console.log('',path);
await writeFile(path, data, e.fileName); await writeFile(path, data, e.fileName, true);
}; };
eventBus.on("saveFile", saveFile); eventBus.on("saveFile", saveFile);
const writeFile = async (path: string, data: any, title: string) => { const writeFile = async (path: string, data: any, title: string, isNewFile: boolean) => {
const isShare = ref(false); const isShare = ref(false);
const isWrite = ref(0); const isWrite = ref(0);
if (isShareFile(path)) { if (isShareFile(path)) {
@ -74,12 +75,12 @@ const writeFile = async (path: string, data: any, title: string) => {
}); });
return; return;
} }
} else if (await sys?.fs.exists(path)) { } else if (await sys?.fs.exists(path) && isNewFile) {
let res = await Dialog.showMessageBox({ let res = await Dialog.showMessageBox({
type: "info", type: "info",
title: "提示", title: "提示",
message: "存在相同的文件名-" + title, message: "存在相同的文件名-" + title,
buttons: ["覆盖文件?", "取消"], buttons: ["覆盖文件", "取消"],
}); });
//console.log(res) //console.log(res)
if (res.response > 0) { if (res.response > 0) {
@ -130,7 +131,6 @@ const eventHandler = async (e: MessageEvent) => {
if (win.config && win.config.path) { if (win.config && win.config.path) {
path = win.config.path; path = win.config.path;
//1
let fileTitleArr = path.split(SP).pop().split("."); let fileTitleArr = path.split(SP).pop().split(".");
let oldExt = fileTitleArr.pop(); let oldExt = fileTitleArr.pop();
let fileTitle = fileTitleArr.join("."); let fileTitle = fileTitleArr.join(".");
@ -141,11 +141,11 @@ const eventHandler = async (e: MessageEvent) => {
path = path.replace("." + oldExt, "." + ext); path = path.replace("." + oldExt, "." + ext);
} }
} else { } else {
choose.saveFile("选择地址", "*", componentID, eventData); choose.saveFile("选择地址", "*", componentID, eventData, ext);
return; return;
// path = `${SP}C${SP}Users${SP}Desktop${SP}${title}.${ext}`; // path = `${SP}C${SP}Users${SP}Desktop${SP}${title}.${ext}`;
} }
writeFile(path, data, title); writeFile(path, data, title, false);
} else if (eventData.type == "initSuccess") { } else if (eventData.type == "initSuccess") {
if (hasInit) { if (hasInit) {
return; return;

10
frontend/src/components/window/MenuFooter.vue

@ -12,7 +12,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { BrowserWindow } from "@/system/window/BrowserWindow"; import { BrowserWindow } from "@/system/window/BrowserWindow";
import { UnwrapNestedRefs, ref } from "vue"; import { UnwrapNestedRefs, ref } from "vue";
import { useChooseStore } from "@/stores/choose";
import { notifyInfo } from "@/util/msg";
// import { emitEvent } from "@/system/event"; // import { emitEvent } from "@/system/event";
const choose = useChooseStore()
const props = defineProps<{ const props = defineProps<{
browserWindow: UnwrapNestedRefs<BrowserWindow>; browserWindow: UnwrapNestedRefs<BrowserWindow>;
}>(); }>();
@ -21,10 +24,15 @@ let fileName = ref('未命名文件')
function cancleSave() { function cancleSave() {
props.browserWindow.close() props.browserWindow.close()
choose.closeSaveFile(props.browserWindow.windowInfo.componentID)
} }
function saveFile() { function saveFile() {
if (fileName.value == '') {
notifyInfo('请输入文件名称')
return
}
emit('translateSavePath','',fileName.value) emit('translateSavePath','',fileName.value)
props.browserWindow.close() cancleSave()
} }
</script> </script>

2
frontend/src/components/window/WindowInner.vue

@ -1,7 +1,7 @@
<template> <template>
<IframeFile v-if="win.url" :src="win.url" :ext="win.ext" :eventType="win.eventType" /> <IframeFile v-if="win.url" :src="win.url" :ext="win.ext" :eventType="win.eventType" />
<Suspense v-else> <Suspense v-else>
<component v-if="win.content" :is="stepComponent(win.content)" :translateSavePath="translateSavePath"></component> <component v-if="win.content" :is="stepComponent(win.content)" :translateSavePath="translateSavePath" :componentID="win.windowInfo.componentID"></component>
<RouterView v-else /> <RouterView v-else />
</Suspense> </Suspense>
<!-- <component :is="window.content"></component> --> <!-- <component :is="window.content"></component> -->

10
frontend/src/components/window/WindowTemplate.vue

@ -25,7 +25,7 @@
<div <div
class="wintmp_main" class="wintmp_main"
:class="{ resizeing: resizemode != 'null' }" :class="{ resizeing: resizemode != 'null', 'saveFileMain':browserWindow.windowInfo.footer}"
@mousedown.stop="predown" @mousedown.stop="predown"
@touchstart.stop.passive="predown" @touchstart.stop.passive="predown"
@contextmenu.stop.prevent @contextmenu.stop.prevent
@ -91,7 +91,7 @@
function translateSavePath (path: string, name?: string) { function translateSavePath (path: string, name?: string) {
if (browserWindow.windowInfo.footer) { if (browserWindow.windowInfo.footer) {
const pos = choose.saveFileContent.findIndex((item) => { const pos = choose.saveFileContent.findIndex((item: any) => {
return item.componentID == browserWindow.windowInfo.componentID return item.componentID == browserWindow.windowInfo.componentID
}) })
if (pos == -1) return if (pos == -1) return
@ -239,7 +239,11 @@
position: relative; position: relative;
} }
} }
.saveFileMain {
:deep(.main) {
height: calc(100% - 60px);
}
}
.topwin { .topwin {
// border: 1px solid #0078d7; // border: 1px solid #0078d7;
// box-shadow: var(--window-top-box-shadow); // box-shadow: var(--window-top-box-shadow);

67
frontend/src/stores/choose.ts

@ -1,14 +1,27 @@
import { defineStore } from "pinia" import { defineStore } from "pinia"
import { BrowserWindow } from "@/system"; import { BrowserWindow } from "@/system";
import { ref } from 'vue'; import { ref } from 'vue';
type ExtMap = {
[key: string]: string | string[]
}
export const useChooseStore = defineStore('chooseStore', () => { export const useChooseStore = defineStore('chooseStore', () => {
const win:any = ref() const win:any = ref()
const path:any = ref([]) const path:any = ref([])
const ifShow = ref(false) const ifShow = ref(false)
let savePath = ref({ const extArr: ExtMap = {
path: '', 'Documents/Word': 'docx',
name: '' 'Documents/PPT': 'pptx',
}) 'Documents/Markdown': 'md',
'Documents/Excel': 'xlsx',
'Documents/Mind': 'mind',
'Documents/Kanban': 'kb',
'Documents/Baiban': 'bb',
'Documents/Screenshot': 'screenshot',
'Documents/ScreenRecoding': 'screentRecording',
'Pictures': ['png','jpg','webp','gif','bmp','tiff'],
'Music': 'mp3',
'Videos': 'mp4'
}
const saveFileContent = ref<any[]>([]) const saveFileContent = ref<any[]>([])
const select = (title = '选择文件', fileExt:any) => { const select = (title = '选择文件', fileExt:any) => {
@ -31,8 +44,11 @@ export const useChooseStore = defineStore('chooseStore', () => {
win.value.show() win.value.show()
ifShow.value = true ifShow.value = true
} }
const saveFile = (title: string, fileExt: any, componentID: string, eventData: any) => { const saveFile = (title: string, fileExt: any, componentID: string, eventData: any, ext: string) => {
// console.log('保存文件'); // console.log('保存文件');
// 判断是否已经存在
if (isExist(componentID)) return
// 打开弹窗
win.value = new BrowserWindow({ win.value = new BrowserWindow({
title, title,
content: "Computer", content: "Computer",
@ -52,29 +68,58 @@ export const useChooseStore = defineStore('chooseStore', () => {
componentID componentID
}); });
win.value.show() win.value.show()
// 默认路径
let defaultPath = ''
Object.keys(extArr).forEach( (item: string) => {
if (extArr[item] &&
((Array.isArray(extArr[item]) && extArr[item].includes(ext)) || extArr[item] == ext)
) {
defaultPath = item
}
})
defaultPath == '' ? defaultPath = '/D' : defaultPath = '/C/Users/' + defaultPath
// console.log('1111111:', defaultPath);
saveFileContent.value.push({ saveFileContent.value.push({
componentID, componentID,
eventData, eventData,
defaultPath,
filePath: '', filePath: '',
fileName: '' fileName: ''
}) })
return savePath
// ifShow.value = true // ifShow.value = true
} }
const close = () => { const close = () => {
ifShow.value = false ifShow.value = false
win.value.close() win.value.close()
}
// 清除缓存
const closeSaveFile = (componentID: string) => {
saveFileContent.value.forEach((item, index) => {
if (item.componentID == componentID) {
saveFileContent.value.splice(index, 1)
}
})
win.value.close()
}
// 判断弹窗是否存在
const isExist = (componentID: string) => {
saveFileContent.value.forEach(item => {
if (item.componentID == componentID) {
return true
}
})
return false
} }
return { return {
win, win,
path, path,
ifShow, ifShow,
savePath,
saveFileContent, saveFileContent,
select, select,
close, close,
saveFile saveFile,
closeSaveFile,
isExist
} }
}) })

10
frontend/src/system/window/Dialog.ts

@ -79,12 +79,18 @@ class Dialog {
}>((resolve) => { }>((resolve) => {
promres = resolve; promres = resolve;
}); });
let confirmText = 'OK'
let cancleText = 'Cancel'
if (option.buttons && option.buttons.length == 2) {
confirmText = option.buttons[0]
cancleText = option.buttons[1]
}
ElMessageBox.confirm( ElMessageBox.confirm(
opt.message, opt.message,
opt.title, opt.title,
{ {
confirmButtonText: 'OK', confirmButtonText: confirmText,
cancelButtonText: 'Cancel', cancelButtonText: cancleText,
type: opt.type, type: opt.type,
} }
) )

Loading…
Cancel
Save