diff --git a/frontend/components.d.ts b/frontend/components.d.ts index c0dc9f1..4bbf6b6 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -67,6 +67,7 @@ declare module 'vue' { ElAside: typeof import('element-plus/es')['ElAside'] ElAvatar: typeof import('element-plus/es')['ElAvatar'] ElBadge: typeof import('element-plus/es')['ElBadge'] + ElBu: typeof import('element-plus/es')['ElBu'] ElButton: typeof import('element-plus/es')['ElButton'] ElCard: typeof import('element-plus/es')['ElCard'] ElCarousel: typeof import('element-plus/es')['ElCarousel'] @@ -84,10 +85,12 @@ declare module 'vue' { ElFooter: typeof import('element-plus/es')['ElFooter'] ElForm: typeof import('element-plus/es')['ElForm'] ElFormItem: typeof import('element-plus/es')['ElFormItem'] + ElFormItm: typeof import('element-plus/es')['ElFormItm'] ElHeader: typeof import('element-plus/es')['ElHeader'] ElIcon: typeof import('element-plus/es')['ElIcon'] ElImage: typeof import('element-plus/es')['ElImage'] ElInput: typeof import('element-plus/es')['ElInput'] + ElItem: typeof import('element-plus/es')['ElItem'] ElMain: typeof import('element-plus/es')['ElMain'] ElOption: typeof import('element-plus/es')['ElOption'] ElPagination: typeof import('element-plus/es')['ElPagination'] diff --git a/frontend/src/components/desktop/LockDesktop.vue b/frontend/src/components/desktop/LockDesktop.vue index 173c2ad..890fec8 100644 --- a/frontend/src/components/desktop/LockDesktop.vue +++ b/frontend/src/components/desktop/LockDesktop.vue @@ -16,7 +16,7 @@ @@ -62,11 +62,13 @@ />
- + > - 注册 + + 注册 + + + + 返回 + -
+
@@ -145,31 +157,33 @@ - 返回
-
+
-
+
- 返回
-
+
@@ -180,33 +194,45 @@ /> - - - + + + + - - + + + + - - - + + + - - - + + 返回 + + 登录 +
@@ -220,7 +246,6 @@ import router from "@/system/router"; import { RestartApp } from "@/util/goutil"; import { notifyError } from "@/util/msg"; - import QRCode from "qrcode"; import { onMounted, ref, watchEffect } from "vue"; import { useRoute } from "vue-router"; const route = useRoute(); @@ -229,12 +254,13 @@ const loginCallback = sys._options.loginCallback; const config = getSystemConfig(); const lockClassName = ref("screen-show"); - const ThirdPartyLoginMethod = ref("login"); + const phoneForm = ref({ phone: "", code: "", }); - // 声明 DTFrameLogin 方法 + + // 声明 DTFrameLogin 和 WwLogin 方法 declare global { interface Window { DTFrameLogin: ( @@ -243,6 +269,13 @@ successCbk: (result: IDTLoginSuccess) => void, errorCbk?: (error: any) => void ) => void; + WwLogin: (options: { + id: string; // 需要显示二维码的元素ID + appid: string; // 微信企业号的应用ID + agentid: string; // 微信企业号的代理ID + redirect_uri: string; // 登录成功后的重定向地址 + state: string; // 用于防止CSRF攻击的状态参数 + }) => void; } } // 包裹容器的尺寸与样式需要接入方自己使用css设置 @@ -282,9 +315,10 @@ await result.json(); } }; + const onDingDingScan = () => { - ThirdPartyLoginMethod.value = "dingding"; + store.ThirdPartyLoginMethod = "dingding"; initDingDingScan(); }; @@ -338,13 +372,34 @@ }); } + const sendCodeButtonText = ref("发送验证码"); + const isSendCodeButtonDisabled = ref(false); + const onSendCode = () => { console.log("发送验证码"); + startCountdown(); + }; + + const startCountdown = () => { + let countdown = 2; + isSendCodeButtonDisabled.value = true; + sendCodeButtonText.value = `${countdown}秒后重试`; + + const interval = setInterval(() => { + countdown--; + if (countdown > 0) { + sendCodeButtonText.value = `${countdown}秒后重试`; + } else { + clearInterval(interval); + sendCodeButtonText.value = "发送验证码"; + isSendCodeButtonDisabled.value = false; + } + }, 1000); }; const thirdPartyPlatforms = [ { - name: "qywechat", + name: "qyweixin", icon: new URL("@/assets/login/qywechat.png", import.meta.url).href, }, { @@ -404,20 +459,28 @@ const platformCodeMap: Record = { github: "github", gitee: "gitee", - qywechat: "qywechat", + qyweixin: "qyweixin_scan", qq: "qq", dingding: "dingtalk_scan", + phone: "sms_code", }; // 获取对应的参数名称 const codeParam = platform ? platformCodeMap[platform] : null; // 根据登录类型传递参数 - const login_type = codeParam ? codeParam : "password"; + let param; + if (codeParam) { + if (platform === "phone") { + param = { phone: phoneForm.value.phone, sms_code: code }; + } else { + param = { code: code }; + } + } else { + param = { username: userName.value, password: userPassword.value }; + } - const param = codeParam - ? { code: code } - : { username: userName.value, password: userPassword.value }; + const login_type = codeParam ? codeParam : "password"; const res = await loginCallback(login_type, param); @@ -436,14 +499,6 @@ RestartApp(); }; - const regForm = ref({ - username: "", - password: "", - confirmPassword: "", - email: "", - phone: "", - nickname: "", - }); const regFormRef: any = ref(null); const rules = { @@ -467,7 +522,7 @@ console.log(rule); if (value === "") { callback(new Error("请再次输入密码")); - } else if (value !== regForm.value.password) { + } else if (value !== store.registerInfo.password) { callback(new Error("两次输入的密码不一致")); } else { callback(); @@ -506,11 +561,10 @@ const onRegister = async () => { try { await regFormRef.value.validate(); - const save = toRaw(regForm.value); const userInfo = config.userInfo; - const comp = await fetch(userInfo.url + "/member/register", { + const comp = await fetch(userInfo.url + "/user/register", { method: "POST", - body: JSON.stringify(save), + body: JSON.stringify(store.registerInfo), }); if (!comp.ok) { notifyError("网络错误,注册失败"); @@ -519,7 +573,12 @@ const res = await comp.json(); if (res.success) { notifyError("注册成功"); - // toggleRegister(); + loginSuccess(); + window.location.href = "/"; + // 设置用户名和密码 + config.userInfo.username = store.registerInfo.username; + config.userInfo.password = store.registerInfo.password; + setSystemConfig(config); } else { notifyError(res.message); return; @@ -566,7 +625,7 @@ return await authWithDingDing(); }; break; - case "qywechat": + case "qyweixin": loginFunction = async function () { return await authWithWechat(); }; @@ -590,10 +649,14 @@ }; const authWithPhone = async (): Promise => { - ThirdPartyLoginMethod.value = "phone"; + store.ThirdPartyLoginMethod = "phone"; return true; }; + const loginByPhone = async () => { + await onLogin(); + }; + const authWithDingDing = async (): Promise => { onDingDingScan(); return true; @@ -619,7 +682,6 @@ } const data = await res.json(); if (data && data.data && data.data.url) { - console.log(data.data.url, "---"); // 使用正则表达式检查URL格式 const urlPattern = /client_id=[^&]+/; if (urlPattern.test(data.data.url)) { @@ -636,29 +698,32 @@ }; const authWithWechat = async (): Promise => { - ThirdPartyLoginMethod.value = "qywechat"; + await loadScript( + "http://rescdn.qqmail.com/node/ww/wwopenmng/js/sso/wwLogin-1.0.0.js" + ); + store.ThirdPartyLoginMethod = "qyweixin"; const res = await fetch( - "http://server001.godoos.com/user/qyweixin/qrcode" + "http://server001.godoos.com/user/qyweixin/conf" ); + if (res.ok) { const data = await res.json(); - if (data.success && data.data.url) { - // 生成二维码 - QRCode.toCanvas( - document.getElementById("qywechat-qr-code"), - data.data.url, - function (error: any) { - if (error) console.error(error); - console.log("二维码生成成功"); - } - ); - } else { - notifyError("获取授权URL失败"); + if (data.success) { + console.log(data.data); + window.WwLogin({ + id: "qywechat-qr-code", + appid: data.data.corp_id, + agentid: data.data.agent_id, + redirect_uri: data.data.redirect, + state: "WWLogin", + }); + return true; } + return false; } else { notifyError("网络错误,无法获取二维码"); + return false; } - return true; }; const authWithGitee = async (): Promise => { @@ -716,7 +781,7 @@ backdrop-filter: blur(7px); .login-box { - width: 300px; + width: 400px; padding: 20px; text-align: center; background: #ffffff; @@ -863,5 +928,31 @@ border-radius: 4px; line-height: 40px; cursor: pointer; + transition: background 0.3s ease; + + &:disabled { + background: #c0c4cc; // 灰色背景 + cursor: not-allowed; // 禁用时的鼠标样式 + } + } + .qywechat { + width: 300px; + height: 400px; + padding: 10px; + margin: 0 auto; + overflow: hidden; + border: 1px solid rgb(203, 203, 203); + border-radius: 10px; + + // 使用 :deep 选择器来确保样式应用到子元素 + :deep(#qywechat-qr-code) { + width: 100%; + height: 100%; + iframe { + width: 100%; + height: 100%; + border: none; // 确保没有额外的边框 + } + } } diff --git a/frontend/src/stores/login.ts b/frontend/src/stores/login.ts index afe143a..9d742f3 100644 --- a/frontend/src/stores/login.ts +++ b/frontend/src/stores/login.ts @@ -10,11 +10,24 @@ export const useLoginStore = defineStore("login", () => { // 临时clientId const tempClientId = ref(""); const ThirdPartyLoginMethod = ref("login"); + + const registerInfo = ref({ + "username": "", + "nickname": "", + "password": "", + "email": "", + "phone": "", + "third_user_id": "", + "union_id": "", + "patform": "", + "confirmPassword": "", + }); return { ThirdPartyPlatform, State, ThirdPartyLoginMethod, tempToken, tempClientId, + registerInfo, }; },); \ No newline at end of file diff --git a/frontend/src/system/dinglogin.ts b/frontend/src/system/dinglogin.ts index ba3c576..f867e09 100644 --- a/frontend/src/system/dinglogin.ts +++ b/frontend/src/system/dinglogin.ts @@ -4,7 +4,7 @@ import { getSystemConfig, setSystemConfig } from "./config"; const config = getSystemConfig(); // 函数用于动态加载外部JS文件 -function loadScript(url: string): Promise { +export function loadScript(url: string): Promise { return new Promise((resolve, reject) => { const script = document.createElement('script') script.src = url @@ -16,14 +16,13 @@ function loadScript(url: string): Promise { const currentUrl = window.location.origin -export async function getCropId(): Promise { +export async function authWithDing(): Promise { try { const res = await fetch(currentUrl + "/user/ding/conf"); const data = await res.json(); console.log(data) if (data.success) { console.log(data.data.id) - alert(data.data.host); return await getCode(data.data.id); } return false; @@ -54,7 +53,7 @@ async function getCode(corpId: string): Promise { // 登录接口 -async function toLogin(this: any, code: string): Promise { +async function toLogin(code: string): Promise { const data = { login_type: "dingtalk_workbench", client_id: GetClientId(), diff --git a/frontend/src/system/index.ts b/frontend/src/system/index.ts index d091a87..a51a708 100644 --- a/frontend/src/system/index.ts +++ b/frontend/src/system/index.ts @@ -26,11 +26,12 @@ import { pick } from '../util/modash'; import { clearSystemConfig, fetchGet, getFileUrl, getSystemConfig, getSystemKey, setSystemConfig, setSystemKey } from './config'; import { OsFileInterface } from './core/FIleInterface'; import { extname } from './core/Path'; -import { getCropId } from './dinglogin.ts'; +import { authWithDing } from './dinglogin.ts'; import { initBuiltinApp, initBuiltinFileOpener } from './initBuiltin'; import { defaultConfig } from './initConfig'; import { Tray, TrayOptions } from './menu/Tary'; import { Notify, NotifyConstructorOptions } from './notification/Notification'; +import { authWithWechat } from './qiyeweixinlogin.ts'; import { Dialog } from './window/Dialog'; export type OsPlugin = (system: System) => void; @@ -102,16 +103,26 @@ export class System { initBuiltinApp(this); initBuiltinFileOpener(this); // 注册内建文件打开器 await this.initSavedConfig(); // 初始化保存的配置 - // 判断是否登录 + + // 判断是否为钉钉工作台登录 const login_type = new URLSearchParams(window.location.search).get("login_type"); if (login_type === "dingding") { - let islogin = await getCropId(); + let islogin = await authWithDing(); alert(islogin); if (!islogin) { - console.log("登录失败,无法继续操作"); + alert("登录失败,无法继续操作"); return; } } + if (login_type === "qiyeweixin") { + let islogin = await authWithWechat(); + if (!islogin) { + alert("登录失败,无法继续操作"); + return; + } + } + + // 判断是否登录 await this.isLogin(); initEventListener(); // 初始化事件侦听 @@ -235,9 +246,20 @@ export class System { if (jsondata.code == 10000) { const loginStore = useLoginStore(); - loginStore.tempToken = jsondata.data.token; - loginStore.tempClientId = jsondata.data.client_id; loginStore.ThirdPartyLoginMethod = "register"; + + // 注册信息 + loginStore.registerInfo = { + username: jsondata.data.username, + nickname: jsondata.data.nickname, + password: jsondata.data.password, + email: jsondata.data.email, + phone: jsondata.data.phone, + third_user_id: jsondata.data.third_user_id, + union_id: jsondata.data.union_id, + patform: jsondata.data.patform, + confirmPassword: "", + } return true; } diff --git a/frontend/src/system/qiyeweixinlogin.ts b/frontend/src/system/qiyeweixinlogin.ts new file mode 100644 index 0000000..690b919 --- /dev/null +++ b/frontend/src/system/qiyeweixinlogin.ts @@ -0,0 +1,42 @@ +import { GetClientId } from "@/util/clientid"; +import { getSystemConfig, setSystemConfig } from "./config"; +const config = getSystemConfig(); +export async function authWithWechat(): Promise { + const queryParams = new URLSearchParams(window.location.search); + const code = queryParams.get("code"); + if (!code) { + alert("登录失败,无法继续操作"); + return false; + } + return await toLogin(code); +} + + +// 登录接口 +async function toLogin(code: string): Promise { + const data = { + login_type: "qyweixin", + client_id: GetClientId(), + param: { + code, + }, + }; + try { + const res = await fetch("http://server001.godoos.com/user/login", { + method: "POST", + body: JSON.stringify(data), + }); + const jsondata = await res.json(); + if (jsondata.success) { + jsondata.data.url = "http://server001.godoos.com"; + config.userInfo = jsondata.data; + config.userType = "member"; + setSystemConfig(config); + window.location.href = "/"; + return true; + } + } catch (error) { + alert(error); + } + return false; +} \ No newline at end of file