mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: login
This commit is contained in:
parent
b1d13f501f
commit
f805f6dce1
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"name": "MaxKB",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
|
|
@ -13,7 +13,9 @@
|
|||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.8.4",
|
||||
"element-plus": "^2.9.7",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.1",
|
||||
"vue": "^3.5.13",
|
||||
"vue-i18n": "^11.1.3",
|
||||
|
|
@ -22,6 +24,7 @@
|
|||
"devDependencies": {
|
||||
"@tsconfig/node22": "^22.0.1",
|
||||
"@types/node": "^22.14.0",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
||||
"@vue/eslint-config-prettier": "^10.2.0",
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ interface LoginRequest {
|
|||
* 密码
|
||||
*/
|
||||
password: string
|
||||
/**
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
code: string
|
||||
captcha: string
|
||||
}
|
||||
export type { LoginRequest }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
interface User {
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
id: string
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
username: string
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
email: string
|
||||
/**
|
||||
* 用户角色
|
||||
*/
|
||||
role: string
|
||||
/**
|
||||
* 用户权限
|
||||
*/
|
||||
permissions: Array<string>
|
||||
/**
|
||||
* 是否需要修改密码
|
||||
*/
|
||||
is_edit_password?: boolean
|
||||
IS_XPACK?: boolean
|
||||
XPACK_LICENSE_IS_VALID?: boolean
|
||||
language: string
|
||||
}
|
||||
|
||||
interface LoginRequest {
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
username: string
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
password: string
|
||||
}
|
||||
|
||||
interface RegisterRequest {
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
username: string
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
password: string
|
||||
/**
|
||||
* 确定密码
|
||||
*/
|
||||
re_password: string
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
email: string
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
code: string
|
||||
}
|
||||
|
||||
interface CheckCodeRequest {
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
email: string
|
||||
/**
|
||||
*验证码
|
||||
*/
|
||||
code: string
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
type: 'register' | 'reset_password'
|
||||
}
|
||||
|
||||
interface ResetCurrentUserPasswordRequest {
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
code: string
|
||||
/**
|
||||
*密码
|
||||
*/
|
||||
password: string
|
||||
/**
|
||||
* 确认密码
|
||||
*/
|
||||
re_password: string
|
||||
}
|
||||
|
||||
interface ResetPasswordRequest {
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
email?: string
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
code?: string
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
password: string
|
||||
/**
|
||||
* 确认密码
|
||||
*/
|
||||
re_password: string
|
||||
}
|
||||
|
||||
export type {
|
||||
LoginRequest,
|
||||
RegisterRequest,
|
||||
CheckCodeRequest,
|
||||
ResetPasswordRequest,
|
||||
User,
|
||||
ResetCurrentUserPasswordRequest
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { Result } from '@/request/Result'
|
||||
import { get, post } from '@/request/index'
|
||||
import type { LoginRequest } from '@/api/type/login'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* @param request 登录接口请求表单
|
||||
* @param loading 接口加载器
|
||||
* @returns 认证数据
|
||||
*/
|
||||
const login: (request: LoginRequest, loading?: Ref<boolean>) => Promise<Result<string>> = (
|
||||
request,
|
||||
loading,
|
||||
) => {
|
||||
return post('/user/login', request, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证码
|
||||
* @param loading 接口加载器
|
||||
*/
|
||||
const getCaptcha: (loading?: Ref<boolean>) => Promise<Result<string>> = (loading) => {
|
||||
return get('/user/captcha', undefined, loading)
|
||||
}
|
||||
|
||||
export default {
|
||||
login,
|
||||
getCaptcha,
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import { Result } from '@/request/Result'
|
||||
import { get, post } from '@/request/index'
|
||||
import type { User } from '@/api/type/user'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
/**
|
||||
* 获取用户基本信息
|
||||
* @param loading 接口加载器
|
||||
* @returns 用户基本信息
|
||||
*/
|
||||
const getUserProfile: (loading?: Ref<boolean>) => Promise<Result<User>> = (loading) => {
|
||||
return get('/user/profile', undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本profile
|
||||
*/
|
||||
// const getProfile: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) => {
|
||||
// return get('/profile', undefined, loading)
|
||||
// }
|
||||
|
||||
export default {
|
||||
getUserProfile,
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import en from 'element-plus/es/locale/lang/en'
|
|||
import components from './components'
|
||||
import layout from './layout'
|
||||
import views from './views'
|
||||
import theme from './theme'
|
||||
import common from './common'
|
||||
import dynamicsForm from './dynamics-form'
|
||||
import chat from './ai-chat'
|
||||
|
|
@ -9,6 +10,7 @@ export default {
|
|||
lang: 'English',
|
||||
layout,
|
||||
views,
|
||||
theme,
|
||||
components,
|
||||
en,
|
||||
common,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
export default {
|
||||
title: 'Appearance Settings',
|
||||
defaultSlogan: 'Ready-to-use, flexible RAG Chatbot',
|
||||
platformDisplayTheme: 'Platform Display Theme',
|
||||
customTheme: 'Custom Theme',
|
||||
platformLoginSettings: 'Platform Login Settings',
|
||||
custom: 'Custom',
|
||||
pagePreview: 'Page Preview',
|
||||
default: 'Default',
|
||||
restoreDefaults: 'Restore Defaults',
|
||||
orange: 'Orange',
|
||||
green: 'Green',
|
||||
purple: 'Purple',
|
||||
red: 'Red',
|
||||
loginBackground: 'Login Background Image',
|
||||
loginLogo: 'Login Logo',
|
||||
websiteLogo: 'Website Logo',
|
||||
replacePicture: 'Replace Image',
|
||||
websiteLogoTip:
|
||||
'Logo displayed at the top of the website. Recommended size: 48x48. Supports JPG, PNG, GIF. Maximum size: 10MB',
|
||||
loginLogoTip:
|
||||
'Logo on the right side of the login page. Recommended size: 204x52. Supports JPG, PNG, GIF. Maximum size: 10MB',
|
||||
loginBackgroundTip:
|
||||
'Left-side background image. Vector graphics recommended size: 576x900; Bitmap recommended size: 1152x1800. Supports JPG, PNG, GIF. Maximum size: 10MB',
|
||||
websiteName: 'Website Name',
|
||||
websiteNamePlaceholder: 'Please enter the website name',
|
||||
websiteNameTip: 'The platform name displayed in the web page tab',
|
||||
websiteSlogan: 'Welcome Slogan',
|
||||
websiteSloganPlaceholder: 'Please enter the welcome slogan',
|
||||
websiteSloganTip: 'The welcome slogan below the product logo',
|
||||
|
||||
defaultTip: 'The default is the MaxKB platform interface, supports custom settings',
|
||||
logoDefaultTip: 'The default is the MaxKB login interface, supports custom settings',
|
||||
platformSetting: 'Platform Settings',
|
||||
showUserManual: 'Show User Manual',
|
||||
showForum: 'Show Forum Support',
|
||||
showProject: 'Show Project Address',
|
||||
urlPlaceholder: 'Please enter the URL address',
|
||||
abandonUpdate: 'Abandon Update',
|
||||
saveAndApply: 'Save and Apply',
|
||||
fileMessageError: 'File size exceeds 10MB',
|
||||
saveSuccess: 'Appearance settings successfully applied',
|
||||
}
|
||||
|
|
@ -1,5 +1,25 @@
|
|||
export default {
|
||||
title: 'Login',
|
||||
loginForm: {
|
||||
username: {
|
||||
label: 'Username',
|
||||
placeholder: 'Please enter username',
|
||||
requiredMessage: 'Please enter username',
|
||||
lengthMessage: 'Length must be between 6 and 20 words',
|
||||
},
|
||||
password: {
|
||||
label: 'Login Password',
|
||||
placeholder: 'Please enter password',
|
||||
requiredMessage: 'Please enter password',
|
||||
lengthMessage: 'Length must be between 6 and 20 words',
|
||||
},
|
||||
captcha: {
|
||||
label: 'Verification Code',
|
||||
placeholder: 'Please enter verification code',
|
||||
requiredMessage: 'Please enter verification code',
|
||||
validatorMessage: 'Verification code is incorrect',
|
||||
},
|
||||
},
|
||||
jump_tip: 'You will be redirected to the authentication source page for authentication',
|
||||
jump: 'Redirect',
|
||||
resetPassword: 'Change Password',
|
||||
|
|
@ -9,7 +29,7 @@ export default {
|
|||
login: 'Login',
|
||||
register: 'Register',
|
||||
backLogin: 'Back to Login',
|
||||
checkCode: 'Verify Now'
|
||||
checkCode: 'Verify Now',
|
||||
},
|
||||
newPassword: 'New Password',
|
||||
enterPassword: 'Please enter your new password',
|
||||
|
|
@ -19,6 +39,6 @@ export default {
|
|||
placeholder: 'Please enter the verification code',
|
||||
getVerificationCode: 'Get Verification Code',
|
||||
successMessage: 'Verification code sent successfully',
|
||||
resend: 'Resend'
|
||||
}
|
||||
resend: 'Resend',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,48 +93,6 @@ export default {
|
|||
access: 'Access'
|
||||
}
|
||||
},
|
||||
theme: {
|
||||
title: 'Appearance Settings',
|
||||
platformDisplayTheme: 'Platform Display Theme',
|
||||
customTheme: 'Custom Theme',
|
||||
platformLoginSettings: 'Platform Login Settings',
|
||||
custom: 'Custom',
|
||||
pagePreview: 'Page Preview',
|
||||
default: 'Default',
|
||||
restoreDefaults: 'Restore Defaults',
|
||||
orange: 'Orange',
|
||||
green: 'Green',
|
||||
purple: 'Purple',
|
||||
red: 'Red',
|
||||
loginBackground: 'Login Background Image',
|
||||
loginLogo: 'Login Logo',
|
||||
websiteLogo: 'Website Logo',
|
||||
replacePicture: 'Replace Image',
|
||||
websiteLogoTip:
|
||||
'Logo displayed at the top of the website. Recommended size: 48x48. Supports JPG, PNG, GIF. Maximum size: 10MB',
|
||||
loginLogoTip:
|
||||
'Logo on the right side of the login page. Recommended size: 204x52. Supports JPG, PNG, GIF. Maximum size: 10MB',
|
||||
loginBackgroundTip:
|
||||
'Left-side background image. Vector graphics recommended size: 576x900; Bitmap recommended size: 1152x1800. Supports JPG, PNG, GIF. Maximum size: 10MB',
|
||||
websiteName: 'Website Name',
|
||||
websiteNamePlaceholder: 'Please enter the website name',
|
||||
websiteNameTip: 'The platform name displayed in the web page tab',
|
||||
websiteSlogan: 'Welcome Slogan',
|
||||
websiteSloganPlaceholder: 'Please enter the welcome slogan',
|
||||
websiteSloganTip: 'The welcome slogan below the product logo',
|
||||
defaultSlogan: 'Ready-to-use, flexible RAG Chatbot',
|
||||
defaultTip: 'The default is the MaxKB platform interface, supports custom settings',
|
||||
logoDefaultTip: 'The default is the MaxKB login interface, supports custom settings',
|
||||
platformSetting: 'Platform Settings',
|
||||
showUserManual: 'Show User Manual',
|
||||
showForum: 'Show Forum Support',
|
||||
showProject: 'Show Project Address',
|
||||
urlPlaceholder: 'Please enter the URL address',
|
||||
abandonUpdate: 'Abandon Update',
|
||||
saveAndApply: 'Save and Apply',
|
||||
fileMessageError: 'File size exceeds 10MB',
|
||||
saveSuccess: 'Appearance settings successfully applied'
|
||||
},
|
||||
email: {
|
||||
title: 'Email Settings',
|
||||
smtpHost: 'SMTP Host',
|
||||
|
|
|
|||
|
|
@ -3,68 +3,57 @@ export default {
|
|||
createUser: 'Create User',
|
||||
editUser: 'Edit User',
|
||||
setting: {
|
||||
updatePwd: 'Change Password'
|
||||
updatePwd: 'Change Password',
|
||||
},
|
||||
tip: {
|
||||
professionalMessage:
|
||||
'The community edition supports up to 2 users. For more users, please upgrade to the professional edition.',
|
||||
updatePwdSuccess: 'User password updated successfully'
|
||||
updatePwdSuccess: 'User password updated successfully',
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: 'Confirm deletion of user:',
|
||||
confirmMessage:
|
||||
'Deleting this user will also delete all resources (APP, knowledge, models) created by this user. Please proceed with caution.'
|
||||
'Deleting this user will also delete all resources (APP, knowledge, models) created by this user. Please proceed with caution.',
|
||||
},
|
||||
disabled: {
|
||||
confirmTitle: 'Confirm disable function:',
|
||||
confirmMessage:
|
||||
'Disabling this function will cause errors when APP that reference it are queried. Please proceed with caution.'
|
||||
'Disabling this function will cause errors when APP that reference it are queried. Please proceed with caution.',
|
||||
},
|
||||
userForm: {
|
||||
form: {
|
||||
username: {
|
||||
label: 'Username',
|
||||
placeholder: 'Please enter username',
|
||||
requiredMessage: 'Please enter username',
|
||||
lengthMessage: 'Length must be between 6 and 20 words'
|
||||
},
|
||||
nick_name: {
|
||||
label: 'Name',
|
||||
placeholder: 'Please enter name'
|
||||
placeholder: 'Please enter name',
|
||||
},
|
||||
email: {
|
||||
label: 'Email',
|
||||
placeholder: 'Please enter email',
|
||||
requiredMessage: 'Please enter email'
|
||||
requiredMessage: 'Please enter email',
|
||||
},
|
||||
phone: {
|
||||
label: 'Phone',
|
||||
placeholder: 'Please enter phone'
|
||||
},
|
||||
password: {
|
||||
label: 'Login Password',
|
||||
placeholder: 'Please enter password',
|
||||
requiredMessage: 'Please enter password',
|
||||
lengthMessage: 'Length must be between 6 and 20 words'
|
||||
placeholder: 'Please enter phone',
|
||||
},
|
||||
|
||||
new_password: {
|
||||
label: 'New Password',
|
||||
placeholder: 'Please enter new password',
|
||||
requiredMessage: 'Please enter new password'
|
||||
requiredMessage: 'Please enter new password',
|
||||
},
|
||||
re_password: {
|
||||
label: 'Confirm Password',
|
||||
placeholder: 'Please enter confirm password',
|
||||
requiredMessage: 'Please enter confirm password',
|
||||
validatorMessage: 'Passwords do not match'
|
||||
}
|
||||
}
|
||||
validatorMessage: 'Passwords do not match',
|
||||
},
|
||||
},
|
||||
},
|
||||
source: {
|
||||
label: 'User Type',
|
||||
local: 'System User',
|
||||
wecom: 'WeCom',
|
||||
lark: 'Lark',
|
||||
dingtalk: 'DingTalk'
|
||||
}
|
||||
dingtalk: 'DingTalk',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
export default {
|
||||
noHistory: '暂无历史记录',
|
||||
createChat: '新建对话',
|
||||
history: '历史记录',
|
||||
only20history: '仅显示最近 20 条对话',
|
||||
question_count: '条提问',
|
||||
exportRecords: '导出聊天记录',
|
||||
chatId: '对话 ID',
|
||||
userInput: '用户输入',
|
||||
quote: '引用',
|
||||
download: '点击下载文件',
|
||||
passwordValidator: {
|
||||
title: '请输入密码打开链接',
|
||||
errorMessage1: '密码不能为空',
|
||||
errorMessage2: '密码错误'
|
||||
},
|
||||
operation: {
|
||||
play: '点击播放',
|
||||
pause: '停止',
|
||||
regeneration: '换个答案',
|
||||
like: '赞同',
|
||||
cancelLike: '取消赞同',
|
||||
oppose: '反对',
|
||||
cancelOppose: '取消反对',
|
||||
continue: '继续',
|
||||
stopChat: '停止回答',
|
||||
startChat: '开始回答',
|
||||
},
|
||||
tip: {
|
||||
error500Message: '抱歉,当前正在维护,无法提供服务,请稍后再试!',
|
||||
errorIdentifyMessage: '无法识别用户身份',
|
||||
errorLimitMessage: '抱歉,您的提问已达到最大限制,请明天再来吧!',
|
||||
answerMessage: '抱歉,没有查找到相关内容,请重新描述您的问题或提供更多信息。',
|
||||
stopAnswer: '已停止回答',
|
||||
answerLoading: '回答中',
|
||||
recorderTip: `<p>该功能需要使用麦克风,浏览器禁止不安全页面录音,解决方案如下:<br/>
|
||||
1、可开启 https 解决;<br/>
|
||||
2、若无 https 配置则需要修改浏览器安全配置,Chrome 设置如下:<br/>
|
||||
(1) 地址栏输入chrome://flags/#unsafely-treat-insecure-origin-as-secure;<br/>
|
||||
(2) 将 http 站点配置在文本框中,例如: http://127.0.0.1:8080。</p>`,
|
||||
recorderError: '录音失败',
|
||||
confirm: '我知道了',
|
||||
requiredMessage: '请填写所有必填字段',
|
||||
inputParamMessage1: '请在URL中填写参数',
|
||||
inputParamMessage2: '的值',
|
||||
prologueMessage: '抱歉,当前正在维护,无法提供服务,请稍后再试!'
|
||||
},
|
||||
inputPlaceholder: {
|
||||
speaking: '说话中',
|
||||
recorderLoading: '转文字中',
|
||||
default: '请输入问题'
|
||||
},
|
||||
uploadFile: {
|
||||
label: '上传文件',
|
||||
most: '最多',
|
||||
limit: '个,每个文件限制',
|
||||
fileType: '文件类型',
|
||||
tipMessage: '请在文件上传配置中选择文件类型',
|
||||
limitMessage1: '最多上传',
|
||||
limitMessage2: '个文件',
|
||||
sizeLimit: '单个文件大小不能超过',
|
||||
imageMessage: '请解析图片内容',
|
||||
errorMessage: '上传失败'
|
||||
},
|
||||
executionDetails: {
|
||||
title: '执行详情',
|
||||
paramOutputTooltip: '每个文档仅支持预览500字',
|
||||
audioFile: '语音文件',
|
||||
searchContent: '检索内容',
|
||||
searchResult: '检索结果',
|
||||
conditionResult: '判断结果',
|
||||
currentChat: '本次对话',
|
||||
answer: 'AI 回答',
|
||||
replyContent: '回复内容',
|
||||
textContent: '文本内容',
|
||||
input: '输入',
|
||||
output: '输出',
|
||||
rerankerContent: '重排内容',
|
||||
rerankerResult: '重排结果',
|
||||
paragraph: '分段',
|
||||
noSubmit: '用户未提交',
|
||||
errMessage: '错误日志'
|
||||
},
|
||||
KnowledgeSource: {
|
||||
title: '知识来源',
|
||||
referenceParagraph: '引用分段',
|
||||
consume: '消耗tokens',
|
||||
consumeTime: '耗时'
|
||||
},
|
||||
paragraphSource: {
|
||||
title: '知识库引用',
|
||||
question: '用户问题',
|
||||
optimizationQuestion: '优化后问题'
|
||||
},
|
||||
editTitle: '编辑标题',
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
export default {
|
||||
create: '创建',
|
||||
createSuccess: '创建成功',
|
||||
copy: '复制',
|
||||
copySuccess: '复制成功',
|
||||
copyError: '复制失败',
|
||||
save: '保存',
|
||||
saveSuccess: '保存成功',
|
||||
delete: '删除',
|
||||
deleteSuccess: '删除成功',
|
||||
setting: '设置',
|
||||
settingSuccess: '设置成功',
|
||||
submit: '提交',
|
||||
submitSuccess: '提交成功',
|
||||
edit: '编辑',
|
||||
editSuccess: '编辑成功',
|
||||
modify: '修改',
|
||||
modifySuccess: '修改成功',
|
||||
cancel: '取消',
|
||||
confirm: '确定',
|
||||
tip: '提示',
|
||||
add: '添加',
|
||||
refresh: '刷新',
|
||||
search: '搜索',
|
||||
clear: '清空',
|
||||
professional: '购买专业版',
|
||||
createDate: '创建日期',
|
||||
createTime: '创建时间',
|
||||
operation: '操作',
|
||||
character: '字符',
|
||||
export: '导出',
|
||||
exportSuccess: '导出成功',
|
||||
unavailable: '(不可用)',
|
||||
public: '公有',
|
||||
private: '私有',
|
||||
paramSetting: '参数设置',
|
||||
creator: '创建者',
|
||||
author: '作者',
|
||||
debug: '调试',
|
||||
required: '必填',
|
||||
noData: '暂无数据',
|
||||
result: '结果',
|
||||
fileUpload: {
|
||||
document: '文档',
|
||||
image: '图片',
|
||||
audio: '音频',
|
||||
video: '视频'
|
||||
},
|
||||
status: {
|
||||
label: '状态',
|
||||
enableSuccess: '启用成功',
|
||||
disableSuccess: '禁用成功'
|
||||
},
|
||||
inputPlaceholder: '请输入',
|
||||
title: '标题',
|
||||
content: '内容',
|
||||
param: {
|
||||
outputParam: '输出参数',
|
||||
inputParam: '输入参数',
|
||||
initParam: '启动参数',
|
||||
},
|
||||
rename:'重命名'
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
export default {
|
||||
quickCreatePlaceholder: '快速创建空白文档',
|
||||
quickCreateName: '文档名称',
|
||||
noData: '无匹配数据',
|
||||
loading: '加载中',
|
||||
noMore: '到底啦!',
|
||||
selectParagraph: {
|
||||
title: '选择分段',
|
||||
error: '仅执行未成功分段',
|
||||
all: '全部分段'
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
export default {
|
||||
input_type_list: {
|
||||
TextInput: '文本框',
|
||||
PasswordInput: '密码框',
|
||||
Slider: '滑块',
|
||||
SwitchInput: '开关',
|
||||
SingleSelect: '单选框',
|
||||
MultiSelect: '多选框',
|
||||
DatePicker: '日期',
|
||||
JsonInput: 'JSON文本框',
|
||||
RadioCard: '选项卡',
|
||||
RadioRow: '单行选项卡'
|
||||
},
|
||||
default: {
|
||||
label: '默认值',
|
||||
placeholder: '请输入默认值',
|
||||
requiredMessage: '为必填属性',
|
||||
show: '显示默认值'
|
||||
},
|
||||
tip: {
|
||||
requiredMessage: '不能为空',
|
||||
jsonMessage: 'JSON格式不正确'
|
||||
},
|
||||
searchBar: {
|
||||
placeholder: '请输入关键字搜索'
|
||||
},
|
||||
paramForm: {
|
||||
field: {
|
||||
label: '参数',
|
||||
placeholder: '请输入参数',
|
||||
requiredMessage: '参数 为必填属性',
|
||||
requiredMessage2: '只能输入字母数字和下划线'
|
||||
},
|
||||
name: {
|
||||
label: '显示名称',
|
||||
placeholder: '请输入显示名称',
|
||||
requiredMessage: '显示名称 为必填属性'
|
||||
},
|
||||
tooltip: {
|
||||
label: '参数提示说明',
|
||||
placeholder: '请输入参数提示说明'
|
||||
},
|
||||
required: {
|
||||
label: '是否必填',
|
||||
requiredMessage: '是否必填 为必填属性'
|
||||
},
|
||||
input_type: {
|
||||
label: '组件类型',
|
||||
placeholder: '请选择组件类型',
|
||||
requiredMessage: '组建类型 为必填属性'
|
||||
}
|
||||
},
|
||||
DatePicker: {
|
||||
placeholder: '选择日期',
|
||||
year: '年',
|
||||
month: '月',
|
||||
date: '日期',
|
||||
datetime: '日期时间',
|
||||
dataType: {
|
||||
label: '时间类型',
|
||||
placeholder: '请选择时间类型'
|
||||
},
|
||||
format: {
|
||||
label: '格式',
|
||||
placeholder: '请选择格式'
|
||||
}
|
||||
},
|
||||
Select: {
|
||||
label: '选项值',
|
||||
placeholder: '请输入选项值'
|
||||
},
|
||||
tag: {
|
||||
label: '标签',
|
||||
placeholder: '请输入选项标签'
|
||||
},
|
||||
Slider: {
|
||||
showInput: {
|
||||
label: '是否带输入框'
|
||||
},
|
||||
valueRange: {
|
||||
label: '取值范围',
|
||||
minRequired: '最小值必填',
|
||||
maxRequired: '最大值必填'
|
||||
},
|
||||
step: {
|
||||
label: '步长值',
|
||||
requiredMessage1: '步长值必填',
|
||||
requiredMessage2: '步长不能为0'
|
||||
}
|
||||
},
|
||||
TextInput: {
|
||||
length: {
|
||||
label: '文本长度',
|
||||
minRequired: '最小长度必填',
|
||||
maxRequired: '最大长度必填',
|
||||
requiredMessage1: '长度在',
|
||||
requiredMessage2: '到',
|
||||
requiredMessage3: '个字符',
|
||||
requiredMessage4: '文本长度为必填参数'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,13 @@
|
|||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
import components from './components'
|
||||
import layout from './layout'
|
||||
// import components from './components'
|
||||
import views from './views'
|
||||
import common from './common'
|
||||
import dynamicsForm from './dynamics-form'
|
||||
import chat from './ai-chat'
|
||||
import theme from './theme'
|
||||
// import common from './common'
|
||||
// import dynamicsForm from './dynamics-form'
|
||||
// import chat from './ai-chat'
|
||||
export default {
|
||||
lang: '简体中文',
|
||||
layout,
|
||||
views,
|
||||
components,
|
||||
zhCn,
|
||||
common,
|
||||
dynamicsForm,
|
||||
chat
|
||||
views,
|
||||
theme
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
export default {
|
||||
github: '项目地址',
|
||||
wiki: '用户手册',
|
||||
forum: '论坛求助',
|
||||
logout: '退出',
|
||||
apiKey: 'API Key 管理',
|
||||
apiServiceAddress: 'API 服务地址',
|
||||
language: '语言',
|
||||
isExpire: '未上传 License 或 License 已过期。',
|
||||
about: {
|
||||
title: '关于',
|
||||
expiredTime: '到期时间',
|
||||
edition: {
|
||||
label: '版本',
|
||||
community: '社区版',
|
||||
professional: '专业版'
|
||||
},
|
||||
version: '版本号',
|
||||
serialNo: '序列号',
|
||||
remark: '备注',
|
||||
update: '更新',
|
||||
authorize: '授权给'
|
||||
},
|
||||
time: {
|
||||
daysLater: '天后',
|
||||
hoursLater: '小时后',
|
||||
expired: '已过期',
|
||||
expiringSoon: '即将到期'
|
||||
},
|
||||
copyright: '版权所有 © 2014-2025 杭州飞致云信息科技有限公司',
|
||||
userManualUrl: 'https://maxkb.cn/docs/',
|
||||
forumUrl: 'https://bbs.fit2cloud.com/c/mk/11'
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
export default {
|
||||
title: '外观设置',
|
||||
defaultSlogan: '欢迎使用 MaxKB 开源 AI 助手',
|
||||
platformDisplayTheme: '平台显示主题',
|
||||
customTheme: '自定义主题',
|
||||
platformLoginSettings: '平台登录设置',
|
||||
custom: '自定义',
|
||||
pagePreview: '页面预览',
|
||||
default: '默认',
|
||||
restoreDefaults: '恢复默认',
|
||||
orange: '活力橙',
|
||||
green: '松石绿',
|
||||
purple: '神秘紫',
|
||||
red: '胭脂红',
|
||||
loginBackground: '登录背景图',
|
||||
loginLogo: '登录 Logo',
|
||||
websiteLogo: '网站 Logo',
|
||||
replacePicture: '替换图片',
|
||||
websiteLogoTip: '顶部网站显示的 Logo,建议尺寸 48*48,支持 JPG、PNG、GIF,大小不超过 10MB',
|
||||
loginLogoTip: '登录页面右侧 Logo,建议尺寸 204*52,支持 JPG、PNG、GIF,大小不超过 10 MB',
|
||||
loginBackgroundTip:
|
||||
'左侧背景图,矢量图建议尺寸 576*900,位图建议尺寸 1152*1800;支持 JPG、PNG、GIF,大小不超过 10 MB',
|
||||
websiteName: '网站名称',
|
||||
websiteNamePlaceholder: '请输入网站名称',
|
||||
websiteNameTip: '显示在网页 Tab 的平台名称',
|
||||
websiteSlogan: '欢迎语',
|
||||
websiteSloganPlaceholder: '请输入欢迎语',
|
||||
websiteSloganTip: '产品 Logo 下的欢迎语',
|
||||
logoDefaultTip: '默认为 MaxKB 登录界面,支持自定义设置',
|
||||
defaultTip: '默认为 MaxKB 平台界面,支持自定义设置',
|
||||
platformSetting: '平台设置',
|
||||
showUserManual: '显示用户手册',
|
||||
showForum: '显示论坛求助',
|
||||
showProject: '显示项目地址',
|
||||
urlPlaceholder: '请输入 URL 地址',
|
||||
abandonUpdate: '放弃更新',
|
||||
saveAndApply: '保存并应用',
|
||||
fileMessageError: '文件大小超过 10M',
|
||||
saveSuccess: '外观设置成功',
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
export default {
|
||||
title: "404",
|
||||
message: "无法访问应用",
|
||||
operate: "返回首页",
|
||||
};
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
export default {
|
||||
title: '概览',
|
||||
appInfo: {
|
||||
header: '应用信息',
|
||||
publicAccessLink: '公开访问链接',
|
||||
openText: '开',
|
||||
closeText: '关',
|
||||
copyLinkText: '复制链接',
|
||||
refreshLinkText: '刷新链接',
|
||||
demo: '演示',
|
||||
embedInWebsite: '嵌入第三方',
|
||||
accessControl: '访问限制',
|
||||
displaySetting: '显示设置',
|
||||
apiAccessCredentials: 'API 访问凭据',
|
||||
apiKey: 'API Key',
|
||||
refreshToken: {
|
||||
msgConfirm1: '是否重新生成公开访问链接?',
|
||||
msgConfirm2:
|
||||
'重新生成公开访问链接会影响嵌入第三方脚本变更,需要将新脚本重新嵌入第三方,请谨慎操作!',
|
||||
refreshSuccess: '刷新成功'
|
||||
},
|
||||
|
||||
APIKeyDialog: {
|
||||
saveSettings: '保存设置',
|
||||
msgConfirm1: '是否删除API Key',
|
||||
msgConfirm2: '删除API Key后将无法恢复,请确认是否删除?',
|
||||
enabledSuccess: '已启用',
|
||||
disabledSuccess: '已禁用'
|
||||
},
|
||||
EditAvatarDialog: {
|
||||
title: '应用头像',
|
||||
customizeUpload: '自定义上传',
|
||||
upload: '上传',
|
||||
default: '默认logo',
|
||||
custom: '自定义',
|
||||
sizeTip: '建议尺寸 32*32,支持 JPG、PNG、GIF,大小不超过 10 MB',
|
||||
fileSizeExceeded: '文件大小超过 10 MB',
|
||||
uploadImagePrompt: '请上传一张图片'
|
||||
},
|
||||
EmbedDialog: {
|
||||
fullscreenModeTitle: '全屏模式',
|
||||
copyInstructions: '复制以下代码进行嵌入',
|
||||
floatingModeTitle: '浮窗模式',
|
||||
mobileModeTitle: '移动端模式'
|
||||
},
|
||||
LimitDialog: {
|
||||
showSourceLabel: '显示知识来源',
|
||||
clientQueryLimitLabel: '每个客户端提问限制',
|
||||
timesDays: '次/天',
|
||||
authentication: '身份验证',
|
||||
authenticationValue: '验证密码',
|
||||
whitelistLabel: '白名单',
|
||||
whitelistPlaceholder:
|
||||
'请输入允许嵌入第三方的源地址,一行一个,如:\nhttp://127.0.0.1:5678\nhttps://dataease.io'
|
||||
},
|
||||
SettingAPIKeyDialog: {
|
||||
dialogTitle: '设置',
|
||||
allowCrossDomainLabel: '允许跨域地址',
|
||||
crossDomainPlaceholder:
|
||||
'请输入允许的跨域地址,开启后不输入跨域地址则不限制。\n跨域地址一行一个,如:\nhttp://127.0.0.1:5678 \nhttps://dataease.io'
|
||||
},
|
||||
SettingDisplayDialog: {
|
||||
dialogTitle: '显示设置',
|
||||
languageLabel: '语言',
|
||||
showSourceLabel: '显示知识来源',
|
||||
showExecutionDetail: '显示执行详情',
|
||||
restoreDefault: '恢复默认',
|
||||
customThemeColor: '自定义主题色',
|
||||
headerTitleFontColor: '头部标题字体颜色',
|
||||
default: '默认',
|
||||
askUserAvatar: '提问用户头像',
|
||||
replace: '替换',
|
||||
imageMessage: '建议尺寸 32*32,支持 JPG、PNG、GIF,大小不超过 10 MB',
|
||||
AIAvatar: 'AI 回复头像',
|
||||
floatIcon: '浮窗入口图标',
|
||||
iconDefaultPosition: '图标默认位置',
|
||||
iconPosition: {
|
||||
left: '左',
|
||||
right: '右',
|
||||
bottom: '下',
|
||||
top: '上'
|
||||
},
|
||||
draggablePosition: '可拖拽位置',
|
||||
showHistory: '显示历史记录',
|
||||
displayGuide: '显示引导图(浮窗模式)',
|
||||
disclaimer: '免责声明',
|
||||
disclaimerValue: '「以上内容均由 AI 生成,仅供参考和借鉴」'
|
||||
}
|
||||
},
|
||||
monitor: {
|
||||
monitoringStatistics: '监控统计',
|
||||
customRange: '自定义范围',
|
||||
startDatePlaceholder: '开始时间',
|
||||
endDatePlaceholder: '结束时间',
|
||||
pastDayOptions: {
|
||||
past7Days: '过去7天',
|
||||
past30Days: '过去30天',
|
||||
past90Days: '过去90天',
|
||||
past183Days: '过去半年',
|
||||
other: '自定义'
|
||||
},
|
||||
charts: {
|
||||
customerTotal: '用户总数',
|
||||
customerNew: '用户新增数',
|
||||
queryCount: '提问次数',
|
||||
tokensTotal: 'Tokens 总数',
|
||||
userSatisfaction: '用户满意度',
|
||||
approval: '赞同',
|
||||
disapproval: '反对'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
export default {
|
||||
node: '节点',
|
||||
nodeName: '节点名称',
|
||||
baseComponent: '基础组件',
|
||||
nodeSetting: '节点设置',
|
||||
workflow: '工作流',
|
||||
searchBar: {
|
||||
placeholder: '按名称搜索'
|
||||
},
|
||||
info: {
|
||||
previewVersion: '预览版本:',
|
||||
saveTime: '保存时间:'
|
||||
},
|
||||
setting: {
|
||||
restoreVersion: '恢复版本',
|
||||
restoreCurrentVersion: '恢复此版本',
|
||||
addComponent: '添加组件',
|
||||
public: '发布',
|
||||
releaseHistory: '发布历史',
|
||||
autoSave: '自动保存',
|
||||
latestRelease: '最近发布',
|
||||
copyParam: '复制参数',
|
||||
debug: '调试',
|
||||
exit: '直接退出',
|
||||
exitSave: '保存并退出',
|
||||
},
|
||||
tip: {
|
||||
publicSuccess: '发布成功',
|
||||
noData: '没有找到相关结果',
|
||||
nameMessage: '名字不能为空!',
|
||||
onlyRight: '只允许从右边的锚点连出',
|
||||
notRecyclable: '不可循环连线',
|
||||
onlyLeft: '只允许连接左边的锚点',
|
||||
applicationNodeError: '该应用不可用',
|
||||
functionNodeError: '该函数不可用',
|
||||
repeatedNodeError: '节点名称已存在!',
|
||||
cannotCopy: '不能被复制',
|
||||
copyError: '已复制节点',
|
||||
paramErrorMessage: '参数已存在: ',
|
||||
saveMessage: '当前的更改尚未保存,是否保存后退出?',
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '确定删除该节点?',
|
||||
deleteMessage: '节点不允许删除'
|
||||
},
|
||||
control: {
|
||||
zoomOut: '缩小',
|
||||
zoomIn: '放大',
|
||||
fitView: '适应',
|
||||
retract: '收起全部节点',
|
||||
extend: '展开全部节点',
|
||||
beautify: '一键美化'
|
||||
},
|
||||
variable: {
|
||||
label: '变量',
|
||||
global: '全局变量',
|
||||
Referencing: '引用变量',
|
||||
ReferencingRequired: '引用变量必填',
|
||||
ReferencingError: '引用变量错误',
|
||||
NoReferencing: '不存在的引用变量',
|
||||
placeholder: '请选择变量'
|
||||
},
|
||||
condition: {
|
||||
title: '执行条件',
|
||||
front: '前置',
|
||||
AND: '所有',
|
||||
OR: '任一',
|
||||
text: '连线节点执行完,执行当前节点'
|
||||
},
|
||||
validate: {
|
||||
startNodeRequired: '开始节点必填',
|
||||
startNodeOnly: '开始节点只能有一个',
|
||||
baseNodeRequired: '基本信息节点必填',
|
||||
baseNodeOnly: '基本信息节点只能有一个',
|
||||
notInWorkFlowNode: '未在流程中的节点',
|
||||
noNextNode: '不存在的下一个节点',
|
||||
nodeUnavailable: '节点不可用',
|
||||
needConnect1: '节点的',
|
||||
needConnect2: '分支需要连接',
|
||||
cannotEndNode: '节点不能当做结束节点'
|
||||
},
|
||||
nodes: {
|
||||
startNode: {
|
||||
label: '开始',
|
||||
question: '用户问题',
|
||||
currentTime: '当前时间'
|
||||
},
|
||||
baseNode: {
|
||||
label: '基本信息',
|
||||
appName: {
|
||||
label: '应用名称'
|
||||
},
|
||||
appDescription: {
|
||||
label: '应用描述'
|
||||
},
|
||||
fileUpload: {
|
||||
label: '文件上传',
|
||||
tooltip: '开启后,问答页面会显示上传文件的按钮。'
|
||||
},
|
||||
FileUploadSetting: {
|
||||
title: '文件上传设置',
|
||||
maxFiles: '单次上传最多文件数',
|
||||
fileLimit: '每个文件最大(MB)',
|
||||
fileUploadType: {
|
||||
label: '上传的文件类型',
|
||||
documentText: '需要使用“文档内容提取”节点解析文档内容',
|
||||
imageText: '需要使用“视觉模型”节点解析图片内容',
|
||||
audioText: '需要使用“语音转文本”节点解析音频内容'
|
||||
}
|
||||
}
|
||||
},
|
||||
aiChatNode: {
|
||||
label: 'AI 对话',
|
||||
text: '与 AI 大模型进行对话',
|
||||
answer: 'AI 回答内容',
|
||||
returnContent: {
|
||||
label: '返回内容',
|
||||
tooltip: `关闭后该节点的内容则不输出给用户。
|
||||
如果你想让用户看到该节点的输出内容,请打开开关。`
|
||||
},
|
||||
defaultPrompt: '已知信息',
|
||||
think: '思考过程'
|
||||
},
|
||||
searchDatasetNode: {
|
||||
label: '知识库检索',
|
||||
text: '关联知识库,查找与问题相关的分段',
|
||||
paragraph_list: '检索结果的分段列表',
|
||||
is_hit_handling_method_list: '满足直接回答的分段列表',
|
||||
result: '检索结果',
|
||||
directly_return: '满足直接回答的分段内容',
|
||||
searchParam: '检索参数',
|
||||
searchQuestion: {
|
||||
label: '检索问题',
|
||||
placeholder: '请选择检索问题',
|
||||
requiredMessage: '请选择检索问题'
|
||||
}
|
||||
},
|
||||
questionNode: {
|
||||
label: '问题优化',
|
||||
text: '根据历史聊天记录优化完善当前问题,更利于匹配知识库分段',
|
||||
result: '问题优化结果',
|
||||
defaultPrompt1: `根据上下文优化和完善用户问题`,
|
||||
defaultPrompt2: `请输出一个优化后的问题。`,
|
||||
systemDefault: '你是一个问题优化大师'
|
||||
},
|
||||
conditionNode: {
|
||||
label: '判断器',
|
||||
text: '根据不同条件执行不同的节点',
|
||||
branch_name: '分支名称',
|
||||
conditions: {
|
||||
label: '条件',
|
||||
info: '符合以下',
|
||||
requiredMessage: '请选择条件'
|
||||
},
|
||||
valueMessage: '请输入值',
|
||||
addCondition: '添加条件',
|
||||
addBranch: '添加分支'
|
||||
},
|
||||
replyNode: {
|
||||
label: '指定回复',
|
||||
text: '指定回复内容,引用变量会转换为字符串进行输出',
|
||||
content: '内容',
|
||||
replyContent: {
|
||||
label: '回复内容',
|
||||
custom: '自定义',
|
||||
reference: '引用变量'
|
||||
}
|
||||
},
|
||||
rerankerNode: {
|
||||
label: '多路召回',
|
||||
text: '使用重排模型对多个知识库的检索结果进行二次召回',
|
||||
result_list: '重排结果列表',
|
||||
result: '重排结果',
|
||||
rerankerContent: {
|
||||
label: '重排内容',
|
||||
requiredMessage: '请选择重排内容'
|
||||
},
|
||||
higher: '高于',
|
||||
ScoreTooltip: 'Score越高相关性越强。',
|
||||
max_paragraph_char_number: '最大引用字符数',
|
||||
reranker_model: {
|
||||
label: '重排模型',
|
||||
placeholder: '请选择重排模型'
|
||||
}
|
||||
},
|
||||
formNode: {
|
||||
label: '表单收集',
|
||||
text: '在问答过程中用于收集用户信息,可以根据收集到表单数据执行后续流程',
|
||||
form_content_format1: '你好,请先填写下面表单内容:',
|
||||
form_content_format2: '填写后请点击【提交】按钮进行提交。',
|
||||
form_data: '表单全部内容',
|
||||
formContent: {
|
||||
label: '表单输出内容',
|
||||
requiredMessage: '请表单输出内容',
|
||||
tooltip: '设置执行该节点输出的内容,{ form } 为表单的占位符。'
|
||||
},
|
||||
formAllContent: '表单全部内容',
|
||||
formSetting: '表单配置'
|
||||
},
|
||||
documentExtractNode: {
|
||||
label: '文档内容提取',
|
||||
text: '提取文档中的内容',
|
||||
content: '文档内容'
|
||||
},
|
||||
imageUnderstandNode: {
|
||||
label: '图片理解',
|
||||
text: '识别出图片中的对象、场景等信息回答用户问题',
|
||||
answer: 'AI 回答内容',
|
||||
model: {
|
||||
label: '视觉模型',
|
||||
requiredMessage: '请选择视觉模型'
|
||||
},
|
||||
image: {
|
||||
label: '选择图片',
|
||||
requiredMessage: '请选择图片'
|
||||
}
|
||||
},
|
||||
variableAssignNode: {
|
||||
label: '变量赋值',
|
||||
text: '更新全局变量的值',
|
||||
assign: '赋值'
|
||||
},
|
||||
imageGenerateNode: {
|
||||
label: '图片生成',
|
||||
text: '根据提供的文本内容生成图片',
|
||||
answer: 'AI 回答内容',
|
||||
model: {
|
||||
label: '图片生成模型',
|
||||
requiredMessage: '请选择图片生成模型'
|
||||
},
|
||||
prompt: {
|
||||
label: '提示词(正向)',
|
||||
tooltip: '正向提示词,用来描述生成图像中期望包含的元素和视觉特点'
|
||||
},
|
||||
negative_prompt: {
|
||||
label: '提示词(负向)',
|
||||
tooltip: '反向提示词,用来描述不希望在画面中看到的内容,可以对画面进行限制。',
|
||||
placeholder: '请描述不想生成的图片内容,比如:颜色、血腥内容'
|
||||
}
|
||||
},
|
||||
speechToTextNode: {
|
||||
label: '语音转文本',
|
||||
text: '将音频通过语音识别模型转换为文本',
|
||||
stt_model: {
|
||||
label: '语音识别模型'
|
||||
},
|
||||
audio: {
|
||||
label: '选择语音文件',
|
||||
placeholder: '请选择语音文件'
|
||||
}
|
||||
},
|
||||
textToSpeechNode: {
|
||||
label: '文本转语音',
|
||||
text: '将文本通过语音合成模型转换为音频',
|
||||
tts_model: {
|
||||
label: '语音识别模型'
|
||||
},
|
||||
content: {
|
||||
label: '选择文本内容'
|
||||
}
|
||||
},
|
||||
functionNode: {
|
||||
label: '自定义函数',
|
||||
text: '通过执行自定义脚本,实现数据处理'
|
||||
},
|
||||
applicationNode: {
|
||||
label: '应用节点'
|
||||
}
|
||||
},
|
||||
compare: {
|
||||
is_null: '为空',
|
||||
is_not_null: '不为空',
|
||||
contain: '包含',
|
||||
not_contain: '不包含',
|
||||
eq: '等于',
|
||||
ge: '大于等于',
|
||||
gt: '大于',
|
||||
le: '小于等于',
|
||||
lt: '小于',
|
||||
len_eq: '长度等于',
|
||||
len_ge: '长度大于等于',
|
||||
len_gt: '长度大于',
|
||||
len_le: '长度小于等于',
|
||||
len_lt: '长度小于'
|
||||
},
|
||||
FileUploadSetting: {}
|
||||
}
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
export default {
|
||||
title: '应用',
|
||||
createApplication: '创建应用',
|
||||
importApplication: '导入应用',
|
||||
copyApplication: '复制应用',
|
||||
workflow: '高级编排',
|
||||
simple: '简单配置',
|
||||
searchBar: {
|
||||
placeholder: '按名称搜索'
|
||||
},
|
||||
setting: {
|
||||
demo: '演示'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '是否删除应用:',
|
||||
confirmMessage: '删除后该应用将不再提供服务,请谨慎操作。'
|
||||
},
|
||||
tip: {
|
||||
ExportError: '导出失败',
|
||||
professionalMessage: '社区版最多支持 5 个应用,如需拥有更多应用,请升级为专业版。',
|
||||
saveErrorMessage: '保存失败,请检查输入或稍后再试',
|
||||
loadingErrorMessage: '加载配置失败,请检查输入或稍后再试'
|
||||
},
|
||||
applicationForm: {
|
||||
title: {
|
||||
appTest: '调试预览',
|
||||
copy: '副本'
|
||||
},
|
||||
form: {
|
||||
appName: {
|
||||
label: '名称',
|
||||
placeholder: '请输入应用名称',
|
||||
requiredMessage: '请输入应用名称'
|
||||
},
|
||||
appDescription: {
|
||||
label: '描述',
|
||||
placeholder: '描述该应用的应用场景及用途,如:XXX 小助手回答用户提出的 XXX 产品使用问题'
|
||||
},
|
||||
appType: {
|
||||
label: '类型',
|
||||
simplePlaceholder: '适合新手创建小助手',
|
||||
workflowPlaceholder: '适合高级用户自定义小助手的工作流'
|
||||
},
|
||||
appTemplate: {
|
||||
blankApp: '空白应用',
|
||||
assistantApp: '知识库问答助手'
|
||||
},
|
||||
aiModel: {
|
||||
label: 'AI 模型',
|
||||
placeholder: '请选择 AI 模型'
|
||||
},
|
||||
roleSettings: {
|
||||
label: '系统角色',
|
||||
placeholder: '你是 xxx 小助手'
|
||||
},
|
||||
prompt: {
|
||||
label: '提示词',
|
||||
noReferences: ' (无引用知识库)',
|
||||
references: ' (引用知识库)',
|
||||
placeholder: '请输入提示词',
|
||||
requiredMessage: '请输入提示词',
|
||||
tooltip:
|
||||
'通过调整提示词内容,可以引导大模型聊天方向,该提示词会被固定在上下文的开头,可以使用变量。',
|
||||
noReferencesTooltip:
|
||||
'通过调整提示词内容,可以引导大模型聊天方向,该提示词会被固定在上下文的开头。可以使用变量:{question} 是用户提出问题的占位符。',
|
||||
referencesTooltip:
|
||||
'通过调整提示词内容,可以引导大模型聊天方向,该提示词会被固定在上下文的开头。可以使用变量:{data} 是引用知识库中分段的占位符;{question} 是用户提出问题的占位符。',
|
||||
defaultPrompt: `已知信息:{data}
|
||||
用户问题:{question}
|
||||
回答要求:
|
||||
- 请使用中文回答用户问题`
|
||||
},
|
||||
historyRecord: {
|
||||
label: '历史聊天记录'
|
||||
},
|
||||
relatedKnowledge: {
|
||||
label: '关联知识库',
|
||||
placeholder: '关联的知识库展示在这里'
|
||||
},
|
||||
multipleRoundsDialogue: '多轮对话',
|
||||
|
||||
prologue: '开场白',
|
||||
defaultPrologue:
|
||||
'您好,我是 XXX 小助手,您可以向我提出 XXX 使用问题。\n- XXX 主要功能有什么?\n- XXX 如何收费?\n- 需要转人工服务',
|
||||
|
||||
problemOptimization: {
|
||||
label: '问题优化',
|
||||
tooltip: '根据历史聊天优化完善当前问题,更利于匹配知识点。'
|
||||
},
|
||||
voiceInput: {
|
||||
label: '语音输入',
|
||||
placeholder: '请选择语音识别模型',
|
||||
requiredMessage: '请选择语音输入模型',
|
||||
autoSend: '自动发送'
|
||||
},
|
||||
voicePlay: {
|
||||
label: '语音播放',
|
||||
placeholder: '请选择语音合成模型',
|
||||
requiredMessage: '请选择语音播放模型',
|
||||
autoPlay: '自动播放',
|
||||
browser: '浏览器播放(免费)',
|
||||
tts: 'TTS模型',
|
||||
listeningTest: '试听'
|
||||
},
|
||||
reasoningContent: {
|
||||
label: '输出思考',
|
||||
tooltip: '请根据模型返回的思考标签设置,标签中间的内容将会认定为思考过程',
|
||||
start: '开始',
|
||||
end: '结束'
|
||||
}
|
||||
},
|
||||
buttons: {
|
||||
publish: '保存并发布',
|
||||
|
||||
addModel: '添加模型'
|
||||
},
|
||||
|
||||
dialog: {
|
||||
addDataset: '添加关联知识库',
|
||||
addDatasetPlaceholder: '所选知识库必须使用相同的 Embedding 模型',
|
||||
selected: '已选',
|
||||
countDataset: '个知识库',
|
||||
|
||||
selectSearchMode: '检索模式',
|
||||
vectorSearch: '向量检索',
|
||||
vectorSearchTooltip: '向量检索是一种基于向量相似度的检索方式,适用于知识库中的大数据量场景。',
|
||||
fullTextSearch: '全文检索',
|
||||
fullTextSearchTooltip:
|
||||
'全文检索是一种基于文本相似度的检索方式,适用于知识库中的小数据量场景。',
|
||||
hybridSearch: '混合检索',
|
||||
hybridSearchTooltip:
|
||||
'混合检索是一种基于向量和文本相似度的检索方式,适用于知识库中的中等数据量场景。',
|
||||
similarityThreshold: '相似度高于',
|
||||
similarityTooltip: '相似度越高相关性越强。',
|
||||
topReferences: '引用分段数 TOP',
|
||||
maxCharacters: '最多引用字符数',
|
||||
noReferencesAction: '无引用知识库分段时',
|
||||
continueQuestioning: '继续向 AI 模型提问',
|
||||
provideAnswer: '指定回答内容',
|
||||
designated_answer:
|
||||
'你好,我是 XXX 小助手,我的知识库只包含了 XXX 产品相关知识,请重新描述您的问题。',
|
||||
defaultPrompt1:
|
||||
'()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在',
|
||||
defaultPrompt2: '标签中'
|
||||
}
|
||||
},
|
||||
applicationAccess: {
|
||||
title: '应用接入',
|
||||
wecom: '企业微信应用',
|
||||
wecomTip: '打造企业微信智能应用',
|
||||
dingtalk: '钉钉应用',
|
||||
dingtalkTip: '打造钉钉智能应用',
|
||||
wechat: '公众号',
|
||||
wechatTip: '打造公众号智能应用',
|
||||
lark: '飞书应用',
|
||||
larkTip: '打造飞书智能应用',
|
||||
slack: 'Slack',
|
||||
slackTip: '打造 Slack 智能应用',
|
||||
setting: '配置',
|
||||
callback: '回调地址',
|
||||
callbackTip: '请输入回调地址',
|
||||
wecomPlatform: '企业微信后台',
|
||||
wechatPlatform: '微信公众平台',
|
||||
dingtalkPlatform: '钉钉开放平台',
|
||||
larkPlatform: '飞书开放平台',
|
||||
wecomSetting: {
|
||||
title: '企业微信应用配置',
|
||||
cropId: '企业 ID',
|
||||
cropIdPlaceholder: '请输入企业 ID',
|
||||
agentIdPlaceholder: '请输入Agent ID',
|
||||
secretPlaceholder: '请输入Secret',
|
||||
tokenPlaceholder: '请输入Token',
|
||||
encodingAesKeyPlaceholder: '请输入EncodingAESKey',
|
||||
authenticationSuccessful: '认证成功',
|
||||
urlInfo: '-应用管理-自建-创建的应用-接收消息-设置 API 接收的 "URL" 中'
|
||||
},
|
||||
dingtalkSetting: {
|
||||
title: '钉钉应用配置',
|
||||
clientIdPlaceholder: '请输入Client ID',
|
||||
clientSecretPlaceholder: '请输入Client Secret',
|
||||
urlInfo: '-机器人页面,设置 "消息接收模式" 为 HTTP模式 ,并把上面URL填写到"消息接收地址"中'
|
||||
},
|
||||
wechatSetting: {
|
||||
title: '公众号应用配置',
|
||||
appId: '开发者ID (APP ID)',
|
||||
appIdPlaceholder: '请输入开发者ID (APP ID)',
|
||||
appSecret: '开发者密钥 (APP SECRET)',
|
||||
appSecretPlaceholder: '请输入开发者密钥 (APP SECRET)',
|
||||
token: '令牌 (TOKEN)',
|
||||
tokenPlaceholder: '请输入令牌 (TOKEN)',
|
||||
aesKey: '消息加解密密钥',
|
||||
aesKeyPlaceholder: '请输入消息加解密密钥',
|
||||
urlInfo: '-设置与开发-基本配置-服务器配置的 "服务器地址URL" 中'
|
||||
},
|
||||
larkSetting: {
|
||||
title: '飞书应用配置',
|
||||
appIdPlaceholder: '请输入App ID',
|
||||
appSecretPlaceholder: '请输入App Secret',
|
||||
verificationTokenPlaceholder: '请输入Verification Token',
|
||||
urlInfo: '-事件与回调-事件配置-配置订阅方式的 "请求地址" 中'
|
||||
},
|
||||
slackSetting: {
|
||||
title: 'Slack 应用配置',
|
||||
signingSecretPlaceholder: '请输入 Signing Secret',
|
||||
botUserTokenPlaceholder: '请输入 Bot User Token'
|
||||
},
|
||||
copyUrl: '复制链接填入到'
|
||||
},
|
||||
hitTest: {
|
||||
title: '命中测试',
|
||||
text: '针对用户提问调试段落匹配情况,保障回答效果。',
|
||||
emptyMessage1: '命中段落显示在这里',
|
||||
emptyMessage2: '没有命中的分段'
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
export default {
|
||||
title: '知识库',
|
||||
createDataset: '创建知识库',
|
||||
general: '通用型',
|
||||
web: 'web 站点',
|
||||
relatedApplications: '关联应用',
|
||||
document_count: '文档数',
|
||||
relatedApp_count: '关联应用',
|
||||
searchBar: {
|
||||
placeholder: '按名称搜索'
|
||||
},
|
||||
setting: {
|
||||
vectorization: '向量化',
|
||||
sync: '同步'
|
||||
},
|
||||
tip: {
|
||||
professionalMessage: '社区版最多支持 50 个知识库,如需拥有更多知识库,请升级为专业版。',
|
||||
syncSuccess: '同步任务发送成功',
|
||||
updateModeMessage: '修改知识库向量模型后,需要对知识库向量化,是否继续保存?'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '是否删除知识库:',
|
||||
confirmMessage1: '此知识库关联',
|
||||
confirmMessage2: '个应用,删除后无法恢复,请谨慎操作。'
|
||||
},
|
||||
|
||||
datasetForm: {
|
||||
title: {
|
||||
info: '基本信息'
|
||||
},
|
||||
form: {
|
||||
datasetName: {
|
||||
label: '知识库名称',
|
||||
placeholder: '请输入知识库名称',
|
||||
requiredMessage: '请输入应用名称'
|
||||
},
|
||||
datasetDescription: {
|
||||
label: '知识库描述',
|
||||
placeholder:
|
||||
'描述知识库的内容,详尽的描述将帮助AI能深入理解该知识库的内容,能更准确的检索到内容,提高该知识库的命中率。',
|
||||
requiredMessage: '请输入知识库描述'
|
||||
},
|
||||
EmbeddingModel: {
|
||||
label: '向量模型',
|
||||
placeholder: '请选择向量模型',
|
||||
requiredMessage: '请输入Embedding模型'
|
||||
},
|
||||
datasetType: {
|
||||
label: '知识库类型',
|
||||
generalInfo: '上传本地文档',
|
||||
webInfo: '同步Web网站文本数据'
|
||||
},
|
||||
source_url: {
|
||||
label: 'Web 根地址',
|
||||
placeholder: '请输入 Web 根地址',
|
||||
requiredMessage: ' 请输入 Web 根地址'
|
||||
},
|
||||
selector: {
|
||||
label: '选择器',
|
||||
placeholder: '默认为 body,可输入 .classname/#idname/tagname'
|
||||
}
|
||||
}
|
||||
},
|
||||
ResultSuccess: {
|
||||
title: '知识库创建成功',
|
||||
paragraph: '分段',
|
||||
paragraph_count: '个分段',
|
||||
documentList: '文档列表',
|
||||
loading: '导入中',
|
||||
buttons: {
|
||||
toDataset: '返回知识库列表',
|
||||
toDocument: '前往文档'
|
||||
}
|
||||
},
|
||||
syncWeb: {
|
||||
title: '同步知识库',
|
||||
syncMethod: '同步方式',
|
||||
replace: '替换同步',
|
||||
replaceText: '重新获取 Web 站点文档,覆盖替换本地知识库中的文档',
|
||||
complete: '整体同步',
|
||||
completeText: '先删除本地知识库所有文档,重新获取 Web 站点文档',
|
||||
tip: '注意:所有同步都会删除已有数据重新获取新数据,请谨慎操作。'
|
||||
}
|
||||
}
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
export default {
|
||||
uploadDocument: '上传文档',
|
||||
importDocument: '导入文档',
|
||||
syncDocument: '同步文档',
|
||||
selected: '已选',
|
||||
items: '项',
|
||||
searchBar: {
|
||||
placeholder: '按 文档名称 搜索'
|
||||
},
|
||||
setting: {
|
||||
migration: '迁移',
|
||||
cancelGenerateQuestion: '取消生成问题',
|
||||
cancelVectorization: '取消向量化',
|
||||
cancelGenerate: '取消生成',
|
||||
export: '导出'
|
||||
},
|
||||
tip: {
|
||||
saveMessage: '当前的更改尚未保存,确认退出吗?',
|
||||
cancelSuccess: '批量取消成功',
|
||||
sendMessage: '发送成功',
|
||||
vectorizationSuccess: '批量向量化成功',
|
||||
nameMessage: '文件名称不能为空!',
|
||||
importMessage: '导入成功',
|
||||
migrationSuccess: '迁移成功'
|
||||
},
|
||||
upload: {
|
||||
selectFile: '选择文件',
|
||||
selectFiles: '选择文件夹',
|
||||
uploadMessage: '拖拽文件至此上传或',
|
||||
formats: '支持格式:',
|
||||
requiredMessage: '请上传文件',
|
||||
errorMessage1: '文件大小超过 100MB',
|
||||
errorMessage2: '文件格式不支持',
|
||||
errorMessage3: '文件不能为空',
|
||||
errorMessage4: '每次最多上传50个文件',
|
||||
template: '模版',
|
||||
download: '下载'
|
||||
},
|
||||
|
||||
fileType: {
|
||||
txt: {
|
||||
label: '文本文件',
|
||||
tip1: '1、文件上传前,建议规范文件的分段标识',
|
||||
tip2: '2、每次最多上传 50 个文件,每个文件不超过 100MB'
|
||||
},
|
||||
table: {
|
||||
label: '表格',
|
||||
tip1: '1、点击下载对应模版并完善信息:',
|
||||
tip2: '2、第一行必须是列标题,且列标题必须是有意义的术语,表中每条记录将作为一个分段',
|
||||
tip3: '3、上传的表格文件中每个 sheet 会作为一个文档,sheet名称为文档名称',
|
||||
tip4: '4、每次最多上传 50 个文件,每个文件不超过 100MB'
|
||||
},
|
||||
QA: {
|
||||
label: 'QA 问答对',
|
||||
tip1: '1、点击下载对应模版并完善信息',
|
||||
tip2: '2、上传的表格文件中每个 sheet 会作为一个文档,sheet名称为文档名称',
|
||||
tip3: '3、每次最多上传 50 个文件,每个文件不超过 100MB'
|
||||
}
|
||||
},
|
||||
setRules: {
|
||||
title: {
|
||||
setting: '设置分段规则',
|
||||
preview: '分段预览'
|
||||
},
|
||||
intelligent: {
|
||||
label: '智能分段(推荐)',
|
||||
text: '不了解如何设置分段规则推荐使用智能分段'
|
||||
},
|
||||
advanced: {
|
||||
label: '高级分段',
|
||||
text: '用户可根据文档规范自行设置分段标识符、分段长度以及清洗规则'
|
||||
},
|
||||
patterns: {
|
||||
label: '分段标识',
|
||||
tooltip: '按照所选符号先后顺序做递归分割,分割结果超出分段长度将截取至分段长度。',
|
||||
placeholder: '请选择'
|
||||
},
|
||||
limit: {
|
||||
label: '分段长度'
|
||||
},
|
||||
with_filter: {
|
||||
label: '自动清洗',
|
||||
text: '去掉重复多余符号空格、空行、制表符'
|
||||
},
|
||||
checkedConnect: {
|
||||
label: '导入时添加分段标题为关联问题(适用于标题为问题的问答对)'
|
||||
}
|
||||
},
|
||||
buttons: {
|
||||
prev: '上一步',
|
||||
next: '下一步',
|
||||
import: '开始导入',
|
||||
preview: '生成预览'
|
||||
},
|
||||
table: {
|
||||
name: '文件名称',
|
||||
char_length: '字符数',
|
||||
paragraph: '分段',
|
||||
all: '全部',
|
||||
updateTime: '更新时间'
|
||||
},
|
||||
fileStatus: {
|
||||
label: '文件状态',
|
||||
SUCCESS: '成功',
|
||||
FAILURE: '失败',
|
||||
EMBEDDING: '索引中',
|
||||
PENDING: '排队中',
|
||||
GENERATE: '生成中',
|
||||
SYNC: '同步中',
|
||||
REVOKE: '取消中',
|
||||
finish: '完成'
|
||||
},
|
||||
enableStatus: {
|
||||
label: '启用状态',
|
||||
enable: '开启',
|
||||
close: '关闭'
|
||||
},
|
||||
sync: {
|
||||
label: '同步',
|
||||
confirmTitle: '确认同步文档?',
|
||||
confirmMessage1: '同步将删除已有数据重新获取新数据,请谨慎操作。',
|
||||
confirmMessage2: '无法同步,请先去设置文档 URL地址',
|
||||
successMessage: '同步文档成功'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle1: '是否批量删除',
|
||||
confirmTitle2: '个文档?',
|
||||
confirmMessage: '所选文档中的分段会跟随删除,请谨慎操作。',
|
||||
successMessage: '批量删除成功',
|
||||
confirmTitle3: '是否删除文档:',
|
||||
confirmMessage1: '此文档下的',
|
||||
confirmMessage2: '个分段都会被删除,请谨慎操作。'
|
||||
},
|
||||
form: {
|
||||
source_url: {
|
||||
label: '文档地址',
|
||||
placeholder: '请输入文档地址,一行一个,地址不正确文档会导入失败。',
|
||||
requiredMessage: '请输入文档地址'
|
||||
},
|
||||
selector: {
|
||||
label: '选择器',
|
||||
placeholder: '默认为 body,可输入 .classname/#idname/tagname'
|
||||
},
|
||||
hit_handling_method: {
|
||||
label: '命中处理方式',
|
||||
tooltip: '用户提问时,命中文档下的分段时按照设置的方式进行处理。'
|
||||
},
|
||||
similarity: {
|
||||
label: '相似度高于',
|
||||
placeholder: '直接返回分段内容',
|
||||
requiredMessage: '请输入相似度'
|
||||
}
|
||||
},
|
||||
hitHandlingMethod: {
|
||||
optimization: '模型优化',
|
||||
directly_return: '直接回答'
|
||||
},
|
||||
generateQuestion: {
|
||||
title: '生成问题',
|
||||
successMessage: '生成问题成功',
|
||||
tip1: '提示词中的 {data} 为分段内容的占位符,执行时替换为分段内容发送给 AI 模型;',
|
||||
tip2: 'AI 模型根据分段内容生成相关问题,请将生成的问题放至',
|
||||
tip3: '标签中,系统会自动关联标签中的问题;',
|
||||
tip4: '生成效果依赖于所选模型和提示词,用户可自行调整至最佳效果。',
|
||||
prompt1: `内容:{data}\n\n请总结上面的内容,并根据内容总结生成 5 个问题。\n回答要求:\n- 请只输出问题;\n- 请将每个问题放置`,
|
||||
prompt2: `标签中。`
|
||||
},
|
||||
feishu: {
|
||||
selectDocument: '选择文档',
|
||||
tip1: '仅支持文档和表格类型,文档会根据标题分段,表格会转为Markdown格式后再分段。',
|
||||
tip2: '系统不存储原始文档,导入文档前,建议规范文档的分段标识。',
|
||||
allCheck: '全选'
|
||||
}
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
export default {
|
||||
title: '函数库',
|
||||
internalTitle: '内置函数',
|
||||
added: '已添加',
|
||||
createFunction: '创建函数',
|
||||
editFunction: '编辑函数',
|
||||
copyFunction: '复制函数',
|
||||
importFunction: '导入函数',
|
||||
searchBar: {
|
||||
placeholder: '按函数名称搜索'
|
||||
},
|
||||
setting: {
|
||||
disabled: '禁用'
|
||||
},
|
||||
tip: {
|
||||
saveMessage: '当前的更改尚未保存,确认退出吗?'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '是否删除函数:',
|
||||
confirmMessage: '删除后,引用了该函数的应用提问时会报错 ,请谨慎操作。'
|
||||
},
|
||||
disabled: {
|
||||
confirmTitle: '是否禁用函数:',
|
||||
confirmMessage: '禁用后,引用了该函数的应用提问时会报错 ,请谨慎操作。'
|
||||
},
|
||||
functionForm: {
|
||||
title: {
|
||||
copy: '副本',
|
||||
baseInfo: '基础信息'
|
||||
},
|
||||
form: {
|
||||
functionName: {
|
||||
label: '名称',
|
||||
placeholder: '请输入函数名称',
|
||||
requiredMessage: '请输入函数名称'
|
||||
},
|
||||
functionDescription: {
|
||||
label: '描述',
|
||||
placeholder: '请输入函数的描述'
|
||||
},
|
||||
permission_type: {
|
||||
label: '权限',
|
||||
requiredMessage: '请选择'
|
||||
},
|
||||
paramName: {
|
||||
label: '参数名',
|
||||
placeholder: '请输入参数名',
|
||||
requiredMessage: '请输入参数名'
|
||||
},
|
||||
dataType: {
|
||||
label: '数据类型'
|
||||
},
|
||||
source: {
|
||||
label: '来源',
|
||||
custom: '自定义',
|
||||
reference: '引用参数'
|
||||
},
|
||||
required: {
|
||||
label: '是否必填'
|
||||
},
|
||||
param: {
|
||||
paramInfo1: '使用函数时显示',
|
||||
paramInfo2: '使用函数时不显示',
|
||||
code: '函数内容(Python)',
|
||||
selectPlaceholder: '请选择参数',
|
||||
inputPlaceholder: '请输入参数值',
|
||||
},
|
||||
debug: {
|
||||
run: '运行',
|
||||
output: '输出',
|
||||
runResult: '运行结果',
|
||||
runSuccess: '运行成功',
|
||||
runFailed: '运行失败'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +1,34 @@
|
|||
import notFound from './404'
|
||||
import application from './application'
|
||||
import applicationOverview from './application-overview'
|
||||
import dataset from './dataset'
|
||||
import system from './system'
|
||||
import functionLib from './function-lib'
|
||||
import user from './user'
|
||||
import team from './team'
|
||||
import template from './template'
|
||||
import document from './document'
|
||||
import paragraph from './paragraph'
|
||||
import problem from './problem'
|
||||
import log from './log'
|
||||
import applicationWorkflow from './application-workflow'
|
||||
// import notFound from './404'
|
||||
// import application from './application'
|
||||
// import applicationOverview from './application-overview'
|
||||
// import dataset from './dataset'
|
||||
// import system from './system'
|
||||
// import functionLib from './function-lib'
|
||||
// import user from './user'
|
||||
// import team from './team'
|
||||
// import template from './template'
|
||||
// import document from './document'
|
||||
// import paragraph from './paragraph'
|
||||
// import problem from './problem'
|
||||
// import log from './log'
|
||||
// import applicationWorkflow from './application-workflow'
|
||||
import login from './login'
|
||||
import operateLog from './operate-log'
|
||||
// import operateLog from './operate-log'
|
||||
export default {
|
||||
notFound,
|
||||
application,
|
||||
applicationOverview,
|
||||
dataset,
|
||||
system,
|
||||
functionLib,
|
||||
user,
|
||||
team,
|
||||
template,
|
||||
document,
|
||||
paragraph,
|
||||
problem,
|
||||
log,
|
||||
applicationWorkflow,
|
||||
// notFound,
|
||||
// application,
|
||||
// applicationOverview,
|
||||
// dataset,
|
||||
// system,
|
||||
// functionLib,
|
||||
// user,
|
||||
// team,
|
||||
// template,
|
||||
// document,
|
||||
// paragraph,
|
||||
// problem,
|
||||
// log,
|
||||
// applicationWorkflow,
|
||||
login,
|
||||
operateLog
|
||||
// operateLog
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
export default {
|
||||
title: '对话日志',
|
||||
delete: {
|
||||
confirmTitle: '是否删除问题:',
|
||||
confirmMessage1: '删除问题关联的',
|
||||
confirmMessage2: '个分段会被取消关联,请谨慎操作。'
|
||||
},
|
||||
buttons: {
|
||||
clearStrategy: '清除策略',
|
||||
prev: '上一条',
|
||||
next: '下一条'
|
||||
},
|
||||
table: {
|
||||
abstract: '摘要',
|
||||
chat_record_count: '对话提问数',
|
||||
user: '用户',
|
||||
feedback: {
|
||||
label: '用户反馈',
|
||||
star: '赞同',
|
||||
trample: '反对'
|
||||
},
|
||||
mark: '改进标注',
|
||||
recenTimes: '最近对话时间'
|
||||
},
|
||||
addToDataset: '添加至知识库',
|
||||
daysText: '天之前的对话记录',
|
||||
selectDataset: '选择知识库',
|
||||
selectDatasetPlaceholder: '请选择知识库',
|
||||
saveToDocument: '保存至文档',
|
||||
documentPlaceholder: '请选择文档',
|
||||
editContent: '修改内容',
|
||||
editMark: '修改标注',
|
||||
form: {
|
||||
content: {
|
||||
placeholder: '请输入内容'
|
||||
},
|
||||
title: {
|
||||
placeholder: '请给当前内容设置一个标题,以便管理查看'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,25 @@
|
|||
export default {
|
||||
title: '普通登录',
|
||||
loginForm: {
|
||||
username: {
|
||||
label: '用户名',
|
||||
placeholder: '请输入用户名',
|
||||
requiredMessage: '请输入用户名',
|
||||
lengthMessage: '长度在 6 到 20 个字符',
|
||||
},
|
||||
password: {
|
||||
label: '登录密码',
|
||||
placeholder: '请输入密码',
|
||||
requiredMessage: '请输入密码',
|
||||
lengthMessage: '长度在 6 到 20 个字符',
|
||||
},
|
||||
captcha: {
|
||||
label: '验证码',
|
||||
placeholder: '请输入验证码',
|
||||
requiredMessage: '请输入验证码',
|
||||
validatorMessage: '验证码不正确',
|
||||
},
|
||||
},
|
||||
jump_tip: '即将跳转至认证源页面进行认证',
|
||||
jump: '跳转',
|
||||
resetPassword: '修改密码',
|
||||
|
|
@ -9,7 +29,7 @@ export default {
|
|||
login: '登录',
|
||||
register: '注册',
|
||||
backLogin: '返回登录',
|
||||
checkCode: '立即验证'
|
||||
checkCode: '立即验证',
|
||||
},
|
||||
newPassword: '新密码',
|
||||
enterPassword: '请输入修改密码',
|
||||
|
|
@ -19,6 +39,6 @@ export default {
|
|||
placeholder: '请输入验证码',
|
||||
getVerificationCode: '获取验证码',
|
||||
successMessage: '验证码发送成功',
|
||||
resend: '重新发送'
|
||||
}
|
||||
resend: '重新发送',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
export default {
|
||||
title: '操作日志',
|
||||
table: {
|
||||
menu: {
|
||||
label: '操作菜单'
|
||||
},
|
||||
operate: {
|
||||
label: '操作'
|
||||
},
|
||||
user: {
|
||||
label: '操作用户'
|
||||
},
|
||||
status: {
|
||||
label: '状态',
|
||||
success: '成功',
|
||||
fail: '失败',
|
||||
all: '全部'
|
||||
},
|
||||
ip_address: {
|
||||
label: 'IP地址'
|
||||
},
|
||||
opt: {
|
||||
label: 'API详情'
|
||||
},
|
||||
operateTime: {
|
||||
label: '操作时间'
|
||||
}
|
||||
},
|
||||
close: '关闭'
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
export default {
|
||||
title: '段落',
|
||||
paragraph_count: '段落',
|
||||
editParagraph: '编辑分段',
|
||||
addParagraph: '添加分段',
|
||||
paragraphDetail: '分段详情',
|
||||
character_count: '个字符',
|
||||
setting: {
|
||||
batchSelected: '批量选择',
|
||||
cancelSelected: '取消选择'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '是否删除段落:',
|
||||
confirmMessage: '删除后无法恢复,请谨慎操作。'
|
||||
},
|
||||
relatedProblem: {
|
||||
title: '关联问题',
|
||||
placeholder: '请选择问题'
|
||||
},
|
||||
form: {
|
||||
paragraphTitle: {
|
||||
label: '分段标题',
|
||||
placeholder: '请输入分段标题'
|
||||
},
|
||||
content: {
|
||||
label: '分段内容',
|
||||
placeholder: '请输入分段内容',
|
||||
requiredMessage1: '请输入分段内容',
|
||||
requiredMessage2: '内容最多不超过 100000 个字'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
export default {
|
||||
title: '问题',
|
||||
createProblem: '创建问题',
|
||||
detailProblem: '问题详情',
|
||||
quickCreateProblem: '快速创建问题',
|
||||
quickCreateName: '问题',
|
||||
tip: {
|
||||
placeholder: '请输入问题,支持输入多个,一行一个。',
|
||||
errorMessage: '问题不能为空!',
|
||||
requiredMessage: '请输入问题',
|
||||
relatedSuccess:'批量关联分段成功'
|
||||
},
|
||||
|
||||
setting: {
|
||||
batchDelete: '批量删除',
|
||||
cancelRelated: '取消关联'
|
||||
},
|
||||
searchBar: {
|
||||
placeholder: '按名称搜索'
|
||||
},
|
||||
table: {
|
||||
paragraph_count: '关联分段数',
|
||||
updateTime: '更新时间'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '是否删除问题:',
|
||||
confirmMessage1: '删除问题关联的',
|
||||
confirmMessage2: '个分段会被取消关联,请谨慎操作。'
|
||||
},
|
||||
relateParagraph: {
|
||||
title: '关联分段',
|
||||
selectDocument: '选择文档',
|
||||
placeholder: '按 文档名称 搜索',
|
||||
selectedParagraph: '已选分段',
|
||||
count: '个'
|
||||
},
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
export default {
|
||||
title: '系统设置',
|
||||
test: '测试连接',
|
||||
testSuccess: '测试连接成功',
|
||||
testFailed: '测试连接失败',
|
||||
password: '密码',
|
||||
authentication: {
|
||||
title: '登录认证',
|
||||
ldap: {
|
||||
title: 'LDAP',
|
||||
address: 'LDAP 地址',
|
||||
serverPlaceholder: '请输入LDAP 地址',
|
||||
bindDN: '绑定DN',
|
||||
bindDNPlaceholder: '请输入绑定 DN',
|
||||
ou: '用户OU',
|
||||
ouPlaceholder: '请输入用户 OU',
|
||||
ldap_filter: '用户过滤器',
|
||||
ldap_filterPlaceholder: '请输入用户过滤器',
|
||||
ldap_mapping: 'LDAP 属性映射',
|
||||
ldap_mappingPlaceholder: '请输入 LDAP 属性映射',
|
||||
enableAuthentication: '启用 LDAP 认证'
|
||||
},
|
||||
cas: {
|
||||
title: 'CAS',
|
||||
ldpUri: 'ldpUri',
|
||||
ldpUriPlaceholder: '请输入ldpUri',
|
||||
validateUrl: '验证地址',
|
||||
validateUrlPlaceholder: '请输入验证地址',
|
||||
redirectUrl: '回调地址',
|
||||
redirectUrlPlaceholder: '请输入回调地址',
|
||||
enableAuthentication: '启用 CAS 认证'
|
||||
},
|
||||
oidc: {
|
||||
title: 'OIDC',
|
||||
authEndpoint: '授权端地址',
|
||||
authEndpointPlaceholder: '请输入授权端地址',
|
||||
tokenEndpoint: 'Token端地址',
|
||||
tokenEndpointPlaceholder: '请输入 Token 端地址',
|
||||
userInfoEndpoint: '用户信息端地址',
|
||||
userInfoEndpointPlaceholder: '请输入用户信息端地址',
|
||||
scopePlaceholder: '请输入连接范围',
|
||||
clientId: '客户端 ID',
|
||||
clientIdPlaceholder: '请输入客户端 ID',
|
||||
clientSecret: '客户端密钥',
|
||||
clientSecretPlaceholder: '请输入客户端密钥',
|
||||
logoutEndpoint: '注销端地址',
|
||||
logoutEndpointPlaceholder: '请输入注销端地址',
|
||||
redirectUrl: '回调地址',
|
||||
redirectUrlPlaceholder: '请输入回调地址',
|
||||
enableAuthentication: '启用 OIDC 认证'
|
||||
},
|
||||
|
||||
oauth2: {
|
||||
title: 'OAuth2',
|
||||
authEndpoint: '授权端地址',
|
||||
authEndpointPlaceholder: '请输入授权端地址',
|
||||
tokenEndpoint: 'Token 端地址',
|
||||
tokenEndpointPlaceholder: '请输入 Token 端地址',
|
||||
userInfoEndpoint: '用户信息端地址',
|
||||
userInfoEndpointPlaceholder: '请输入用户信息端地址',
|
||||
scope: '连接范围',
|
||||
scopePlaceholder: '请输入连接范围',
|
||||
clientId: '客户端 ID',
|
||||
clientIdPlaceholder: '请输入客户端 ID',
|
||||
clientSecret: '客户端密钥',
|
||||
clientSecretPlaceholder: '请输入客户端密钥',
|
||||
redirectUrl: '回调地址',
|
||||
redirectUrlPlaceholder: '请输入回调地址',
|
||||
filedMapping: '字段映射',
|
||||
filedMappingPlaceholder: '请输入字段映射',
|
||||
enableAuthentication: '启用 OAuth2 认证'
|
||||
},
|
||||
scanTheQRCode: {
|
||||
title: '扫码登录',
|
||||
wecom: '企业微信',
|
||||
dingtalk: '钉钉',
|
||||
lark: '飞书',
|
||||
effective: '有效',
|
||||
alreadyTurnedOn: '已开启',
|
||||
notEnabled: '未开启',
|
||||
validate: '校验',
|
||||
validateSuccess: '校验成功',
|
||||
validateFailed: '校验失败',
|
||||
validateFailedTip: '请填写所有必填项并确保格式正确',
|
||||
appKeyPlaceholder: '请输入 App Key',
|
||||
appSecretPlaceholder: '请输入 App Secret',
|
||||
corpIdPlaceholder: '请输入 Corp Id',
|
||||
agentIdPlaceholder: '请输入 Agent Id',
|
||||
callbackWarning: '请输入有效的 URL 地址',
|
||||
larkQrCode: '飞书扫码登录',
|
||||
dingtalkQrCode: '钉钉扫码登录',
|
||||
setting: '设置',
|
||||
access: '接入'
|
||||
}
|
||||
},
|
||||
theme: {
|
||||
title: '外观设置',
|
||||
platformDisplayTheme: '平台显示主题',
|
||||
customTheme: '自定义主题',
|
||||
platformLoginSettings: '平台登录设置',
|
||||
custom: '自定义',
|
||||
pagePreview: '页面预览',
|
||||
default: '默认',
|
||||
restoreDefaults: '恢复默认',
|
||||
orange: '活力橙',
|
||||
green: '松石绿',
|
||||
purple: '神秘紫',
|
||||
red: '胭脂红',
|
||||
loginBackground: '登录背景图',
|
||||
loginLogo: '登录 Logo',
|
||||
websiteLogo: '网站 Logo',
|
||||
replacePicture: '替换图片',
|
||||
websiteLogoTip: '顶部网站显示的 Logo,建议尺寸 48*48,支持 JPG、PNG、GIF,大小不超过 10MB',
|
||||
loginLogoTip: '登录页面右侧 Logo,建议尺寸 204*52,支持 JPG、PNG、GIF,大小不超过 10 MB',
|
||||
loginBackgroundTip:
|
||||
'左侧背景图,矢量图建议尺寸 576*900,位图建议尺寸 1152*1800;支持 JPG、PNG、GIF,大小不超过 10 MB',
|
||||
websiteName: '网站名称',
|
||||
websiteNamePlaceholder: '请输入网站名称',
|
||||
websiteNameTip: '显示在网页 Tab 的平台名称',
|
||||
websiteSlogan: '欢迎语',
|
||||
websiteSloganPlaceholder: '请输入欢迎语',
|
||||
websiteSloganTip: '产品 Logo 下的欢迎语',
|
||||
defaultSlogan: '欢迎使用 MaxKB 智能知识库问答系统',
|
||||
logoDefaultTip: '默认为 MaxKB 登录界面,支持自定义设置',
|
||||
defaultTip: '默认为 MaxKB 平台界面,支持自定义设置',
|
||||
platformSetting: '平台设置',
|
||||
showUserManual: '显示用户手册',
|
||||
showForum: '显示论坛求助',
|
||||
showProject: '显示项目地址',
|
||||
urlPlaceholder: '请输入 URL 地址',
|
||||
abandonUpdate: '放弃更新',
|
||||
saveAndApply: '保存并应用',
|
||||
fileMessageError: '文件大小超过 10M',
|
||||
saveSuccess: '外观设置成功'
|
||||
},
|
||||
email: {
|
||||
title: '邮箱设置',
|
||||
smtpHost: 'SMTP Host',
|
||||
smtpHostPlaceholder: '请输入 SMTP Host',
|
||||
smtpPort: 'SMTP Port',
|
||||
smtpPortPlaceholder: '请输入 SMTP Port',
|
||||
smtpUser: 'SMTP 账户',
|
||||
smtpUserPlaceholder: '请输入 SMTP 账户',
|
||||
sendEmail: '发件人邮箱',
|
||||
sendEmailPlaceholder: '请输入发件人邮箱',
|
||||
smtpPassword: '发件人密码',
|
||||
smtpPasswordPlaceholder: '请输入发件人密码',
|
||||
enableSSL: '启用 SSL(如果 SMTP 端口是 465,通常需要启用 SSL)',
|
||||
enableTLS: '启用 TLS(如果 SMTP 端口是 587,通常需要启用 TLS)'
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
export default {
|
||||
title: '团队成员',
|
||||
member: '成员',
|
||||
manage: '所有者',
|
||||
permissionSetting: '权限设置',
|
||||
addMember: '添加成员',
|
||||
addSubTitle: '成员登录后可以访问到您授权的数据。',
|
||||
searchBar: {
|
||||
placeholder: '请输入用户名搜索'
|
||||
},
|
||||
delete: {
|
||||
button: '移除',
|
||||
confirmTitle: '是否移除成员:',
|
||||
confirmMessage: '移除后将会取消成员拥有的知识库和应用权限。'
|
||||
},
|
||||
setting: {
|
||||
management: '管理',
|
||||
check: '查看'
|
||||
},
|
||||
teamForm: {
|
||||
form: {
|
||||
userName: {
|
||||
label: '用户名/邮箱',
|
||||
placeholder: '请输入成员的用户名或邮箱',
|
||||
requiredMessage: '请输入用户名/邮箱'
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
export default {
|
||||
title: '模型设置',
|
||||
provider: '供应商',
|
||||
providerPlaceholder: '选择供应商',
|
||||
addModel: '添加模型',
|
||||
searchBar: {
|
||||
placeholder: '按名称搜索'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '删除模型',
|
||||
confirmMessage: '是否删除模型:'
|
||||
},
|
||||
tip: {
|
||||
createSuccessMessage: '创建模型成功',
|
||||
createErrorMessage: '基础信息有填写错误',
|
||||
errorMessage: '变量已存在: ',
|
||||
emptyMessage1: '请先选择基础信息的模型类型和基础模型',
|
||||
emptyMessage2: '所选模型不支持参数设置',
|
||||
updateSuccessMessage: '修改模型成功',
|
||||
saveSuccessMessage: '模型参数保存成功',
|
||||
downloadError: '下载失败',
|
||||
noModel: '模型在Ollama不存在'
|
||||
},
|
||||
model: {
|
||||
allModel: '全部模型',
|
||||
publicModel: '公有模型',
|
||||
privateModel: '私有模型',
|
||||
LLM: '大语言模型',
|
||||
EMBEDDING: '向量模型',
|
||||
RERANKER: '重排模型',
|
||||
STT: '语音识别',
|
||||
TTS: '语音合成',
|
||||
IMAGE: '视觉模型',
|
||||
TTI: '图片生成'
|
||||
},
|
||||
templateForm: {
|
||||
title: {
|
||||
baseInfo: '基础信息',
|
||||
advancedInfo: '高级设置',
|
||||
modelParams: '模型参数',
|
||||
editParam: '编辑参数',
|
||||
addParam: '添加参数',
|
||||
paramSetting: '模型参数设置',
|
||||
apiParamPassing: '接口传参'
|
||||
},
|
||||
form: {
|
||||
templateName: {
|
||||
label: '模型名称',
|
||||
placeholder: '请给基础模型设置一个名称',
|
||||
tooltip: 'MaxKB 中自定义的模型名称',
|
||||
requiredMessage: '模型名称不能为空'
|
||||
},
|
||||
permissionType: {
|
||||
label: '权限',
|
||||
privateDesc: '仅当前用户使用',
|
||||
publicDesc: '所有用户都可使用',
|
||||
requiredMessage: '权限不能为空'
|
||||
},
|
||||
model_type: {
|
||||
label: '模型类型',
|
||||
placeholder: '请选择模型类型',
|
||||
tooltip1: '大语言模型:在应用中与AI对话的推理模型。',
|
||||
tooltip2: '向量模型:在知识库中对文档内容进行向量化的模型。',
|
||||
tooltip3: '语音识别:在应用中开启语音识别后用于语音转文字的模型。',
|
||||
tooltip4: '语音合成:在应用中开启语音播放后用于文字转语音的模型。',
|
||||
tooltip5: '重排模型:在高级编排应用中使用多路召回时,对候选分段进行重新排序的模型。',
|
||||
tooltip6: '视觉模型:在高级编排应用中用于图片理解的视觉模型。',
|
||||
tooltip7: '图片生成:在高级编排应用中用于图片生成的视觉模型。',
|
||||
requiredMessage: '模型类型不能为空'
|
||||
},
|
||||
base_model: {
|
||||
label: '基础模型',
|
||||
tooltip: '列表中未列出的模型,直接输入模型名称,回车即可添加',
|
||||
placeholder: '自定义输入基础模型后回车即可',
|
||||
requiredMessage: '基础模型不能为空'
|
||||
}
|
||||
}
|
||||
},
|
||||
download: {
|
||||
downloading: '正在下载中',
|
||||
cancelDownload: '取消下载'
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
export default {
|
||||
title: '用户管理',
|
||||
createUser: '创建用户',
|
||||
editUser: '编辑用户',
|
||||
setting: {
|
||||
updatePwd: '修改用户密码'
|
||||
},
|
||||
tip: {
|
||||
professionalMessage: '社区版最多支持 2 个用户,如需拥有更多用户,请升级为专业版。',
|
||||
updatePwdSuccess: '修改用户密码成功'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '是否删除用户:',
|
||||
confirmMessage: '删除用户,该用户创建的资源(应用、知识库、模型)都会删除,请谨慎操作。'
|
||||
},
|
||||
disabled: {
|
||||
confirmTitle: '是否禁用函数:',
|
||||
confirmMessage: '禁用后,引用了该函数的应用提问时会报错 ,请谨慎操作。'
|
||||
},
|
||||
userForm: {
|
||||
form: {
|
||||
username: {
|
||||
label: '用户名',
|
||||
placeholder: '请输入用户名',
|
||||
requiredMessage: '请输入用户名',
|
||||
lengthMessage: '长度在 6 到 20 个字符'
|
||||
},
|
||||
nick_name: {
|
||||
label: '姓名',
|
||||
placeholder: '请输入姓名'
|
||||
},
|
||||
email: {
|
||||
label: '邮箱',
|
||||
placeholder: '请输入邮箱',
|
||||
requiredMessage: '请输入邮箱',
|
||||
validatorEmail: '请输入有效邮箱格式!',
|
||||
},
|
||||
phone: {
|
||||
label: '手机号',
|
||||
placeholder: '请输入手机号'
|
||||
},
|
||||
password: {
|
||||
label: '登录密码',
|
||||
placeholder: '请输入密码',
|
||||
requiredMessage: '请输入密码',
|
||||
lengthMessage: '长度在 6 到 20 个字符'
|
||||
},
|
||||
new_password: {
|
||||
label: '新密码',
|
||||
placeholder: '请输入新密码',
|
||||
requiredMessage: '请输入新密码',
|
||||
},
|
||||
re_password: {
|
||||
label: '确认密码',
|
||||
placeholder: '请输入确认密码',
|
||||
requiredMessage: '请输入确认密码',
|
||||
validatorMessage: '密码不一致',
|
||||
}
|
||||
}
|
||||
},
|
||||
source: {
|
||||
label: '用户类型',
|
||||
local: '系统用户',
|
||||
wecom: '企业微信',
|
||||
lark: '飞书',
|
||||
dingtalk: '钉钉'
|
||||
}
|
||||
}
|
||||
|
|
@ -2,16 +2,18 @@ import zhTw from 'element-plus/es/locale/lang/zh-tw'
|
|||
import components from './components'
|
||||
import layout from './layout'
|
||||
import views from './views'
|
||||
import theme from './theme'
|
||||
import common from './common'
|
||||
import dynamicsForm from './dynamics-form'
|
||||
import chat from './ai-chat'
|
||||
export default {
|
||||
lang: '繁體中文',
|
||||
layout,
|
||||
common,
|
||||
views,
|
||||
theme,
|
||||
common,
|
||||
components,
|
||||
zhTw,
|
||||
dynamicsForm,
|
||||
chat
|
||||
chat,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
export default {
|
||||
title: '外觀設置',
|
||||
defaultSlogan: '歡迎使用 MaxKB 智能知識庫問答系統',
|
||||
platformDisplayTheme: '平台顯示主題',
|
||||
customTheme: '自定義主題',
|
||||
platformLoginSettings: '平台登錄設置',
|
||||
custom: '自定義',
|
||||
pagePreview: '頁面預覽',
|
||||
default: '默認',
|
||||
restoreDefaults: '恢復默認',
|
||||
orange: '活力橙',
|
||||
green: '松石綠',
|
||||
purple: '神秘紫',
|
||||
red: '胭脂紅',
|
||||
loginBackground: '登錄背景圖',
|
||||
loginLogo: '登錄 Logo',
|
||||
websiteLogo: '網站 Logo',
|
||||
replacePicture: '替換圖片',
|
||||
websiteLogoTip: '頂部網站顯示的 Logo,建議尺寸 48*48,支持 JPG、PNG、GIF,大小不超過 10MB',
|
||||
loginLogoTip: '登錄頁面右側 Logo,建議尺寸 204*52,支持 JPG、PNG、GIF,大小不超過 10 MB',
|
||||
loginBackgroundTip:
|
||||
'左側背景圖,矢量圖建議尺寸 576*900,位圖建議尺寸 1152*1800;支持 JPG、PNG、GIF,大小不超過 10 MB',
|
||||
websiteName: '網站名稱',
|
||||
websiteNamePlaceholder: '請輸入網站名稱',
|
||||
websiteNameTip: '顯示在網頁 Tab 的平台名稱',
|
||||
websiteSlogan: '歡迎語',
|
||||
websiteSloganPlaceholder: '請輸入歡迎語',
|
||||
websiteSloganTip: '產品 Logo 下的歡迎語',
|
||||
logoDefaultTip: '默认为 MaxKB 登錄界面,支持自定义设置',
|
||||
|
||||
defaultTip: '默認為 MaxKB 平台界面,支持自定義設置',
|
||||
platformSetting: '平台設置',
|
||||
showUserManual: '顯示用戶手冊',
|
||||
showForum: '顯示論壇求助',
|
||||
showProject: '顯示項目地址',
|
||||
urlPlaceholder: '請輸入 URL 地址',
|
||||
abandonUpdate: '放棄更新',
|
||||
saveAndApply: '保存並應用',
|
||||
fileMessageError: '文件大小超過 10M',
|
||||
saveSuccess: '外觀設置成功',
|
||||
}
|
||||
|
|
@ -1,5 +1,25 @@
|
|||
export default {
|
||||
title: '普通登錄',
|
||||
loginForm: {
|
||||
username: {
|
||||
label: '使用者名稱',
|
||||
placeholder: '請輸入使用者名稱',
|
||||
requiredMessage: '請輸入使用者名稱',
|
||||
lengthMessage: '長度須介於 6 到 20 個字元之間'
|
||||
},
|
||||
password: {
|
||||
label: '登入密碼',
|
||||
placeholder: '請輸入密碼',
|
||||
requiredMessage: '請輸入密碼',
|
||||
lengthMessage: '長度須介於 6 到 20 個字元之間'
|
||||
},
|
||||
captcha: {
|
||||
label: '驗證碼',
|
||||
placeholder: '請輸入驗證碼',
|
||||
requiredMessage: '請輸入驗證碼',
|
||||
validatorMessage: '驗證碼不正確',
|
||||
},
|
||||
},
|
||||
jump_tip: '即將跳轉至認證源頁面進行認證',
|
||||
jump: '跳轉',
|
||||
resetPassword: '修改密碼',
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export default {
|
|||
ldap_filterPlaceholder: '請輸入使用者過濾器',
|
||||
ldap_mapping: 'LDAP 屬性對應',
|
||||
ldap_mappingPlaceholder: '請輸入 LDAP 屬性對應',
|
||||
enableAuthentication: '啟用 LDAP 認證'
|
||||
enableAuthentication: '啟用 LDAP 認證',
|
||||
},
|
||||
cas: {
|
||||
title: 'CAS',
|
||||
|
|
@ -29,7 +29,7 @@ export default {
|
|||
validateUrlPlaceholder: '請輸入驗證位址',
|
||||
redirectUrl: '回呼位址',
|
||||
redirectUrlPlaceholder: '請輸入回呼位址',
|
||||
enableAuthentication: '啟用 CAS 認證'
|
||||
enableAuthentication: '啟用 CAS 認證',
|
||||
},
|
||||
oidc: {
|
||||
title: 'OIDC',
|
||||
|
|
@ -48,7 +48,7 @@ export default {
|
|||
logoutEndpointPlaceholder: '請輸入登出端位址',
|
||||
redirectUrl: '回呼位址',
|
||||
redirectUrlPlaceholder: '請輸入回呼位址',
|
||||
enableAuthentication: '啟用 OIDC 認證'
|
||||
enableAuthentication: '啟用 OIDC 認證',
|
||||
},
|
||||
|
||||
oauth2: {
|
||||
|
|
@ -69,7 +69,7 @@ export default {
|
|||
redirectUrlPlaceholder: '請輸入回呼位址',
|
||||
filedMapping: '欄位對應',
|
||||
filedMappingPlaceholder: '請輸入欄位對應',
|
||||
enableAuthentication: '啟用 OAuth2 認證'
|
||||
enableAuthentication: '啟用 OAuth2 認證',
|
||||
},
|
||||
scanTheQRCode: {
|
||||
title: '掃碼登入',
|
||||
|
|
@ -91,49 +91,10 @@ export default {
|
|||
larkQrCode: '飛書掃碼登錄',
|
||||
dingtalkQrCode: '釘釘掃碼登錄',
|
||||
setting: '設置',
|
||||
access: '接入'
|
||||
}
|
||||
},
|
||||
theme: {
|
||||
title: '外觀設置',
|
||||
platformDisplayTheme: '平台顯示主題',
|
||||
customTheme: '自定義主題',
|
||||
platformLoginSettings: '平台登錄設置',
|
||||
custom: '自定義',
|
||||
pagePreview: '頁面預覽',
|
||||
default: '默認',
|
||||
restoreDefaults: '恢復默認',
|
||||
orange: '活力橙',
|
||||
green: '松石綠',
|
||||
purple: '神秘紫',
|
||||
red: '胭脂紅',
|
||||
loginBackground: '登錄背景圖',
|
||||
loginLogo: '登錄 Logo',
|
||||
websiteLogo: '網站 Logo',
|
||||
replacePicture: '替換圖片',
|
||||
websiteLogoTip: '頂部網站顯示的 Logo,建議尺寸 48*48,支持 JPG、PNG、GIF,大小不超過 10MB',
|
||||
loginLogoTip: '登錄頁面右側 Logo,建議尺寸 204*52,支持 JPG、PNG、GIF,大小不超過 10 MB',
|
||||
loginBackgroundTip:
|
||||
'左側背景圖,矢量圖建議尺寸 576*900,位圖建議尺寸 1152*1800;支持 JPG、PNG、GIF,大小不超過 10 MB',
|
||||
websiteName: '網站名稱',
|
||||
websiteNamePlaceholder: '請輸入網站名稱',
|
||||
websiteNameTip: '顯示在網頁 Tab 的平台名稱',
|
||||
websiteSlogan: '歡迎語',
|
||||
websiteSloganPlaceholder: '請輸入歡迎語',
|
||||
websiteSloganTip: '產品 Logo 下的歡迎語',
|
||||
logoDefaultTip: '默认为 MaxKB 登錄界面,支持自定义设置',
|
||||
defaultSlogan: '歡迎使用 MaxKB 智能知識庫問答系統',
|
||||
defaultTip: '默認為 MaxKB 平台界面,支持自定義設置',
|
||||
platformSetting: '平台設置',
|
||||
showUserManual: '顯示用戶手冊',
|
||||
showForum: '顯示論壇求助',
|
||||
showProject: '顯示項目地址',
|
||||
urlPlaceholder: '請輸入 URL 地址',
|
||||
abandonUpdate: '放棄更新',
|
||||
saveAndApply: '保存並應用',
|
||||
fileMessageError: '文件大小超過 10M',
|
||||
saveSuccess: '外觀設置成功'
|
||||
access: '接入',
|
||||
},
|
||||
},
|
||||
|
||||
email: {
|
||||
title: '郵箱設置',
|
||||
smtpHost: 'SMTP Host',
|
||||
|
|
@ -147,6 +108,6 @@ export default {
|
|||
smtpPassword: '發件人密碼',
|
||||
smtpPasswordPlaceholder: '請輸入發件人密碼',
|
||||
enableSSL: '啟用 SSL(如果 SMTP 端口是 465,通常需要啟用 SSL)',
|
||||
enableTLS: '啟用 TLS(如果 SMTP 端口是 587,通常需要啟用 TLS)'
|
||||
}
|
||||
enableTLS: '啟用 TLS(如果 SMTP 端口是 587,通常需要啟用 TLS)',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
export class Result<T> {
|
||||
message: string
|
||||
code: number
|
||||
data: T
|
||||
constructor(message: string, code: number, data: T) {
|
||||
this.message = message
|
||||
this.code = code
|
||||
this.data = data
|
||||
}
|
||||
|
||||
static success(data: any) {
|
||||
return new Result('请求成功', 200, data)
|
||||
}
|
||||
static error(message: string, code: number) {
|
||||
return new Result(message, code, null)
|
||||
}
|
||||
}
|
||||
|
||||
export default Result
|
||||
|
|
@ -0,0 +1,349 @@
|
|||
import axios, { type InternalAxiosRequestConfig, AxiosHeaders } from 'axios'
|
||||
import { MsgError } from '@/utils/message'
|
||||
import type { NProgress } from 'nprogress'
|
||||
import type { Ref } from 'vue'
|
||||
import type { Result } from '@/request/Result'
|
||||
import useStore from '@/stores'
|
||||
import router from '@/router'
|
||||
|
||||
import { ref, type WritableComputedRef } from 'vue'
|
||||
|
||||
const axiosConfig = {
|
||||
baseURL: '/api',
|
||||
withCredentials: false,
|
||||
timeout: 600000,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const instance = axios.create(axiosConfig)
|
||||
|
||||
/* 设置请求拦截器 */
|
||||
instance.interceptors.request.use(
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
if (config.headers === undefined) {
|
||||
config.headers = new AxiosHeaders()
|
||||
}
|
||||
const { user, login } = useStore()
|
||||
const token = login.getToken()
|
||||
const language = user.getLanguage()
|
||||
config.headers['Accept-Language'] = `${language}`
|
||||
if (token) {
|
||||
config.headers['AUTHORIZATION'] = `${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
(err: any) => {
|
||||
return Promise.reject(err)
|
||||
},
|
||||
)
|
||||
|
||||
//设置响应拦截器
|
||||
instance.interceptors.response.use(
|
||||
(response: any) => {
|
||||
if (response.data) {
|
||||
if (response.data.code !== 200 && !(response.data instanceof Blob)) {
|
||||
if (response.config.url.includes('/application/authentication')) {
|
||||
return Promise.reject(response.data)
|
||||
}
|
||||
if (
|
||||
!response.config.url.includes('/valid') &&
|
||||
!response.config.url.includes('/function_lib/debug')
|
||||
) {
|
||||
MsgError(response.data.message)
|
||||
return Promise.reject(response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
return response
|
||||
},
|
||||
(err: any) => {
|
||||
if (err.code === 'ECONNABORTED') {
|
||||
MsgError(err.message)
|
||||
console.error(err)
|
||||
}
|
||||
if (err.response?.status === 404) {
|
||||
if (!err.response.config.url.includes('/application/authentication')) {
|
||||
router.push('/404 ')
|
||||
}
|
||||
}
|
||||
if (err.response?.status === 401) {
|
||||
if (
|
||||
!err.response.config.url.includes('chat/open') &&
|
||||
!err.response.config.url.includes('application/profile')
|
||||
) {
|
||||
router.push({ name: 'login' })
|
||||
}
|
||||
}
|
||||
|
||||
if (err.response?.status === 403 && !err.response.config.url.includes('chat/open')) {
|
||||
MsgError(
|
||||
err.response.data && err.response.data.message ? err.response.data.message : '没有权限访问',
|
||||
)
|
||||
}
|
||||
return Promise.reject(err)
|
||||
},
|
||||
)
|
||||
|
||||
export const request = instance
|
||||
|
||||
/* 简化请求方法,统一处理返回结果,并增加loading处理,这里以{success,data,message}格式的返回值为例,具体项目根据实际需求修改 */
|
||||
const promise: (
|
||||
request: Promise<any>,
|
||||
loading?: NProgress | Ref<boolean> | WritableComputedRef<boolean>,
|
||||
) => Promise<Result<any>> = (request, loading = ref(false)) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if ((loading as NProgress).start) {
|
||||
;(loading as NProgress).start()
|
||||
} else {
|
||||
;(loading as Ref).value = true
|
||||
}
|
||||
request
|
||||
.then((response) => {
|
||||
// blob类型的返回状态是response.status
|
||||
if (response.status === 200) {
|
||||
resolve(response?.data || response)
|
||||
} else {
|
||||
reject(response?.data || response)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
.finally(() => {
|
||||
if ((loading as NProgress).start) {
|
||||
;(loading as NProgress).done()
|
||||
} else {
|
||||
;(loading as Ref).value = false
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送get请求 一般用来请求资源
|
||||
* @param url 资源url
|
||||
* @param params 参数
|
||||
* @param loading loading
|
||||
* @returns 异步promise对象
|
||||
*/
|
||||
export const get: (
|
||||
url: string,
|
||||
params?: unknown,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
timeout?: number,
|
||||
) => Promise<Result<any>> = (
|
||||
url: string,
|
||||
params: unknown,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
timeout?: number,
|
||||
) => {
|
||||
return promise(request({ url: url, method: 'get', params, timeout: timeout }), loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* faso post请求 一般用来添加资源
|
||||
* @param url 资源url
|
||||
* @param params 参数
|
||||
* @param data 添加数据
|
||||
* @param loading loading
|
||||
* @returns 异步promise对象
|
||||
*/
|
||||
export const post: (
|
||||
url: string,
|
||||
data?: unknown,
|
||||
params?: unknown,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
timeout?: number,
|
||||
) => Promise<Result<any> | any> = (url, data, params, loading, timeout) => {
|
||||
return promise(request({ url: url, method: 'post', data, params, timeout }), loading)
|
||||
}
|
||||
|
||||
/**|
|
||||
* 发送put请求 用于修改服务器资源
|
||||
* @param url 资源地址
|
||||
* @param params params参数地址
|
||||
* @param data 需要修改的数据
|
||||
* @param loading 进度条
|
||||
* @returns
|
||||
*/
|
||||
export const put: (
|
||||
url: string,
|
||||
data?: unknown,
|
||||
params?: unknown,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
timeout?: number,
|
||||
) => Promise<Result<any>> = (url, data, params, loading, timeout) => {
|
||||
return promise(request({ url: url, method: 'put', data, params, timeout }), loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param url 删除url
|
||||
* @param params params参数
|
||||
* @param loading 进度条
|
||||
* @returns
|
||||
*/
|
||||
export const del: (
|
||||
url: string,
|
||||
params?: unknown,
|
||||
data?: unknown,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
timeout?: number,
|
||||
) => Promise<Result<any>> = (url, params, data, loading, timeout) => {
|
||||
return promise(request({ url: url, method: 'delete', params, data, timeout }), loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 流处理
|
||||
* @param url url地址
|
||||
* @param data 请求body
|
||||
* @returns
|
||||
*/
|
||||
export const postStream: (url: string, data?: unknown) => Promise<Result<any> | any> = (
|
||||
url,
|
||||
data,
|
||||
) => {
|
||||
const { user, login } = useStore()
|
||||
const token = login.getToken()
|
||||
const language = user.getLanguage()
|
||||
const headers: HeadersInit = { 'Content-Type': 'application/json' }
|
||||
if (token) {
|
||||
headers['AUTHORIZATION'] = `${token}`
|
||||
}
|
||||
headers['Accept-Language'] = `${language}`
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
headers: headers,
|
||||
})
|
||||
}
|
||||
|
||||
export const exportExcel: (
|
||||
fileName: string,
|
||||
url: string,
|
||||
params: any,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
) => Promise<any> = (
|
||||
fileName: string,
|
||||
url: string,
|
||||
params: any,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
) => {
|
||||
return promise(request({ url: url, method: 'get', params, responseType: 'blob' }), loading).then(
|
||||
(res: any) => {
|
||||
if (res) {
|
||||
const blob = new Blob([res], {
|
||||
type: 'application/vnd.ms-excel',
|
||||
})
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = fileName
|
||||
link.click()
|
||||
//释放内存
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
}
|
||||
return true
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const exportFile: (
|
||||
fileName: string,
|
||||
url: string,
|
||||
params: any,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
) => Promise<any> = (
|
||||
fileName: string,
|
||||
url: string,
|
||||
params: any,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
) => {
|
||||
return promise(request({ url: url, method: 'get', params, responseType: 'blob' }), loading).then(
|
||||
(res: any) => {
|
||||
if (res) {
|
||||
const blob = new Blob([res], {
|
||||
type: 'application/octet-stream',
|
||||
})
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = fileName
|
||||
link.click()
|
||||
//释放内存
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
}
|
||||
return true
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const exportExcelPost: (
|
||||
fileName: string,
|
||||
url: string,
|
||||
params: any,
|
||||
data: any,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
) => Promise<any> = (
|
||||
fileName: string,
|
||||
url: string,
|
||||
params: any,
|
||||
data: any,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
) => {
|
||||
return promise(
|
||||
request({
|
||||
url: url,
|
||||
method: 'post',
|
||||
params, // 查询字符串参数
|
||||
data, // 请求体数据
|
||||
responseType: 'blob',
|
||||
}),
|
||||
loading,
|
||||
).then((res: any) => {
|
||||
if (res) {
|
||||
const blob = new Blob([res], {
|
||||
type: 'application/vnd.ms-excel',
|
||||
})
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = fileName
|
||||
link.click()
|
||||
// 释放内存
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
export const download: (
|
||||
url: string,
|
||||
method: string,
|
||||
data?: any,
|
||||
params?: any,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
) => Promise<any> = (
|
||||
url: string,
|
||||
method: string,
|
||||
data?: any,
|
||||
params?: any,
|
||||
loading?: NProgress | Ref<boolean>,
|
||||
) => {
|
||||
return promise(request({ url: url, method: method, data, params, responseType: 'blob' }), loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 与服务器建立ws链接
|
||||
* @param url websocket路径
|
||||
* @returns 返回一个websocket实例
|
||||
*/
|
||||
export const socket = (url: string) => {
|
||||
let protocol = 'ws://'
|
||||
if (window.location.protocol === 'https:') {
|
||||
protocol = 'wss://'
|
||||
}
|
||||
let uri = protocol + window.location.host + url
|
||||
if (!import.meta.env.DEV) {
|
||||
uri = protocol + window.location.host + import.meta.env.VITE_BASE_PATH + url
|
||||
}
|
||||
return new WebSocket(uri)
|
||||
}
|
||||
export default instance
|
||||
|
|
@ -1,9 +1,82 @@
|
|||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { hasPermission } from '@/utils/permission/index'
|
||||
import NProgress from 'nprogress'
|
||||
import {
|
||||
createRouter,
|
||||
createWebHistory,
|
||||
type NavigationGuardNext,
|
||||
type RouteLocationNormalized,
|
||||
type RouteRecordRaw,
|
||||
type RouteRecordName,
|
||||
} from 'vue-router'
|
||||
import useStore from '@/stores'
|
||||
import { routes } from '@/router/routes'
|
||||
|
||||
NProgress.configure({ showSpinner: false, speed: 500, minimum: 0.3 })
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: routes,
|
||||
})
|
||||
|
||||
// 路由前置拦截器
|
||||
router.beforeEach(
|
||||
async (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
|
||||
NProgress.start()
|
||||
if (to.name === '404') {
|
||||
next()
|
||||
return
|
||||
}
|
||||
const { user, login } = useStore()
|
||||
const notAuthRouteNameList = ['register', 'login', 'forgot_password', 'reset_password', 'Chat']
|
||||
|
||||
if (!notAuthRouteNameList.includes(to.name ? to.name.toString() : '')) {
|
||||
if (to.query && to.query.token) {
|
||||
localStorage.setItem('token', to.query.token.toString())
|
||||
}
|
||||
const token = login.getToken()
|
||||
if (!token) {
|
||||
next({
|
||||
path: '/login',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!user.userInfo) {
|
||||
await user.profile()
|
||||
}
|
||||
}
|
||||
// 判断是否有菜单权限
|
||||
if (to.meta.permission ? hasPermission(to.meta.permission as any, 'OR') : true) {
|
||||
next()
|
||||
} else {
|
||||
// 如果没有权限则直接取404页面
|
||||
next('404')
|
||||
}
|
||||
},
|
||||
)
|
||||
router.afterEach(() => {
|
||||
NProgress.done()
|
||||
})
|
||||
|
||||
export const getChildRouteListByPathAndName = (path: any, name?: RouteRecordName | any) => {
|
||||
return getChildRouteList(routes, path, name)
|
||||
}
|
||||
|
||||
export const getChildRouteList: (
|
||||
routeList: Array<RouteRecordRaw>,
|
||||
path: string,
|
||||
name?: RouteRecordName | null | undefined,
|
||||
) => Array<RouteRecordRaw> = (routeList, path, name) => {
|
||||
for (let index = 0; index < routeList.length; index++) {
|
||||
const route = routeList[index]
|
||||
if (name === route.name && path === route.path) {
|
||||
return route.children || []
|
||||
}
|
||||
if (route.children && route.children.length > 0) {
|
||||
const result = getChildRouteList(route.children, path, name)
|
||||
if (result && result?.length > 0) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
export default router
|
||||
|
|
|
|||
|
|
@ -1,210 +1,43 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { type Ref } from 'vue'
|
||||
// import type { User } from '@/api/type/user'
|
||||
// import { cloneDeep } from 'lodash'
|
||||
// import UserApi from '@/api/user'
|
||||
// import ThemeApi from '@/api/theme'
|
||||
// import { useElementPlusTheme } from 'use-element-plus-theme'
|
||||
// import { defaultPlatformSetting } from '@/utils/theme'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
import { localeConfigKey, getBrowserLang } from '@/locales/index'
|
||||
export interface userStateTypes {
|
||||
userType: number // 1 系统操作者 2 对话用户
|
||||
// userInfo: User | null
|
||||
token: any
|
||||
version?: string
|
||||
userAccessToken?: string
|
||||
XPACK_LICENSE_IS_VALID: false
|
||||
isXPack: false
|
||||
themeInfo: any
|
||||
}
|
||||
import loginApi from '@/api/user/login'
|
||||
import type { LoginRequest } from '@/api/type/login'
|
||||
import useUserStore from './user'
|
||||
|
||||
const useLoginStore = defineStore('login',{
|
||||
state: (): userStateTypes => ({
|
||||
userType: 1,
|
||||
// userInfo: null,
|
||||
const useLoginStore = defineStore('login', {
|
||||
state: () => ({
|
||||
token: '',
|
||||
version: '',
|
||||
userAccessToken: '',
|
||||
XPACK_LICENSE_IS_VALID: false,
|
||||
isXPack: false,
|
||||
themeInfo: null
|
||||
}),
|
||||
actions: {
|
||||
// getLanguage() {
|
||||
// return this.userType === 1
|
||||
// ? localStorage.getItem('MaxKB-locale') || getBrowserLang()
|
||||
// : sessionStorage.getItem('language') || getBrowserLang()
|
||||
// },
|
||||
// showXpack() {
|
||||
// return this.isXPack
|
||||
// },
|
||||
// isDefaultTheme() {
|
||||
// return !this.themeInfo?.theme || this.themeInfo?.theme === '#3370FF'
|
||||
// },
|
||||
// setTheme(data: any) {
|
||||
// const { changeTheme } = useElementPlusTheme(this.themeInfo?.theme)
|
||||
// changeTheme(data?.['theme'])
|
||||
// this.themeInfo = cloneDeep(data)
|
||||
// },
|
||||
// isExpire() {
|
||||
// return this.isXPack && !this.XPACK_LICENSE_IS_VALID
|
||||
// },
|
||||
// isEnterprise() {
|
||||
// return this.isXPack && this.XPACK_LICENSE_IS_VALID
|
||||
// },
|
||||
// getToken(): String | null {
|
||||
// if (this.token) {
|
||||
// return this.token
|
||||
// }
|
||||
// return this.userType === 1 ? localStorage.getItem('token') : this.getAccessToken()
|
||||
// },
|
||||
// getAccessToken() {
|
||||
// const token = sessionStorage.getItem(`${this.userAccessToken}-accessToken`)
|
||||
// if (token) {
|
||||
// return token
|
||||
// }
|
||||
// const local_token = localStorage.getItem(`${token}-accessToken`)
|
||||
// if (local_token) {
|
||||
// return local_token
|
||||
// }
|
||||
// return localStorage.getItem(`accessToken`)
|
||||
// },
|
||||
getToken(): String | null {
|
||||
if (this.token) {
|
||||
return this.token
|
||||
}
|
||||
const user = useUserStore()
|
||||
return user.userType === 1 ? localStorage.getItem('token') : this.getAccessToken()
|
||||
},
|
||||
getAccessToken() {
|
||||
const token = sessionStorage.getItem(`${this.userAccessToken}-accessToken`)
|
||||
if (token) {
|
||||
return token
|
||||
}
|
||||
const local_token = localStorage.getItem(`${token}-accessToken`)
|
||||
if (local_token) {
|
||||
return local_token
|
||||
}
|
||||
return localStorage.getItem(`accessToken`)
|
||||
},
|
||||
|
||||
// getPermissions() {
|
||||
// if (this.userInfo) {
|
||||
// return this.isXPack && this.XPACK_LICENSE_IS_VALID
|
||||
// ? [...this.userInfo?.permissions, 'x-pack']
|
||||
// : this.userInfo?.permissions
|
||||
// } else {
|
||||
// return []
|
||||
// }
|
||||
// },
|
||||
// getRole() {
|
||||
// if (this.userInfo) {
|
||||
// return this.userInfo?.role
|
||||
// } else {
|
||||
// return ''
|
||||
// }
|
||||
// },
|
||||
// changeUserType(num: number, token?: string) {
|
||||
// this.userType = num
|
||||
// this.userAccessToken = token
|
||||
// },
|
||||
|
||||
// async asyncGetProfile() {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// UserApi.getProfile()
|
||||
// .then(async (ok) => {
|
||||
// this.version = ok.data?.version || '-'
|
||||
// this.isXPack = ok.data?.IS_XPACK
|
||||
// this.XPACK_LICENSE_IS_VALID = ok.data?.XPACK_LICENSE_IS_VALID
|
||||
|
||||
// if (this.isEnterprise()) {
|
||||
// await this.theme()
|
||||
// } else {
|
||||
// this.themeInfo = {
|
||||
// ...defaultPlatformSetting
|
||||
// }
|
||||
// }
|
||||
// resolve(ok)
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// reject(error)
|
||||
// })
|
||||
// })
|
||||
// },
|
||||
|
||||
// async theme(loading?: Ref<boolean>) {
|
||||
// return await ThemeApi.getThemeInfo(loading).then((ok) => {
|
||||
// this.setTheme(ok.data)
|
||||
// // window.document.title = this.themeInfo['title'] || 'MaxKB'
|
||||
// // const link = document.querySelector('link[rel="icon"]') as any
|
||||
// // if (link) {
|
||||
// // link['href'] = this.themeInfo['icon'] || '/favicon.ico'
|
||||
// // }
|
||||
// })
|
||||
// },
|
||||
|
||||
// async profile() {
|
||||
// return UserApi.profile().then(async (ok) => {
|
||||
// this.userInfo = ok.data
|
||||
// useLocalStorage(localeConfigKey, 'en-US').value = ok.data?.language || this.getLanguage()
|
||||
// return this.asyncGetProfile()
|
||||
// })
|
||||
// },
|
||||
|
||||
// async login(auth_type: string, username: string, password: string) {
|
||||
// return UserApi.login(auth_type, { username, password }).then((ok) => {
|
||||
// this.token = ok.data
|
||||
// localStorage.setItem('token', ok.data)
|
||||
// return this.profile()
|
||||
// })
|
||||
// },
|
||||
// async dingCallback(code: string) {
|
||||
// return UserApi.getDingCallback(code).then((ok) => {
|
||||
// this.token = ok.data
|
||||
// localStorage.setItem('token', ok.data)
|
||||
// return this.profile()
|
||||
// })
|
||||
// },
|
||||
// async dingOauth2Callback(code: string) {
|
||||
// return UserApi.getDingOauth2Callback(code).then((ok) => {
|
||||
// this.token = ok.data
|
||||
// localStorage.setItem('token', ok.data)
|
||||
// return this.profile()
|
||||
// })
|
||||
// },
|
||||
// async wecomCallback(code: string) {
|
||||
// return UserApi.getWecomCallback(code).then((ok) => {
|
||||
// this.token = ok.data
|
||||
// localStorage.setItem('token', ok.data)
|
||||
// return this.profile()
|
||||
// })
|
||||
// },
|
||||
// async larkCallback(code: string) {
|
||||
// return UserApi.getlarkCallback(code).then((ok) => {
|
||||
// this.token = ok.data
|
||||
// localStorage.setItem('token', ok.data)
|
||||
// return this.profile()
|
||||
// })
|
||||
// },
|
||||
|
||||
// async logout() {
|
||||
// return UserApi.logout().then(() => {
|
||||
// localStorage.removeItem('token')
|
||||
// return true
|
||||
// })
|
||||
// },
|
||||
// async getAuthType() {
|
||||
// return UserApi.getAuthType().then((ok) => {
|
||||
// return ok.data
|
||||
// })
|
||||
// },
|
||||
// async getQrType() {
|
||||
// return UserApi.getQrType().then((ok) => {
|
||||
// return ok.data
|
||||
// })
|
||||
// },
|
||||
// async getQrSource() {
|
||||
// return UserApi.getQrSource().then((ok) => {
|
||||
// return ok.data
|
||||
// })
|
||||
// },
|
||||
// async postUserLanguage(lang: string, loading?: Ref<boolean>) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// UserApi.postLanguage({ language: lang }, loading)
|
||||
// .then(async (ok) => {
|
||||
// useLocalStorage(localeConfigKey, 'en-US').value = lang
|
||||
// window.location.reload()
|
||||
// resolve(ok)
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// reject(error)
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
}
|
||||
async asyncLogin(data: LoginRequest, loading?: Ref<boolean>) {
|
||||
return loginApi.login(data).then((ok) => {
|
||||
this.token = ok.data
|
||||
localStorage.setItem('token', ok.data)
|
||||
const user = useUserStore()
|
||||
return user.profile()
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default useLoginStore
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { type Ref } from 'vue'
|
||||
// import type { User } from '@/api/type/user'
|
||||
import type { User } from '@/api/type/user'
|
||||
import { cloneDeep } from 'lodash'
|
||||
// import UserApi from '@/api/user'
|
||||
import UserApi from '@/api/user/user'
|
||||
// import ThemeApi from '@/api/theme'
|
||||
// import { useElementPlusTheme } from 'use-element-plus-theme'
|
||||
// import { defaultPlatformSetting } from '@/utils/theme'
|
||||
|
|
@ -10,10 +10,8 @@ import { useLocalStorage } from '@vueuse/core'
|
|||
import { localeConfigKey, getBrowserLang } from '@/locales/index'
|
||||
export interface userStateTypes {
|
||||
userType: number // 1 系统操作者 2 对话用户
|
||||
// userInfo: User | null
|
||||
token: any
|
||||
userInfo: User | null
|
||||
version?: string
|
||||
userAccessToken?: string
|
||||
XPACK_LICENSE_IS_VALID: false
|
||||
isXPack: false
|
||||
themeInfo: any
|
||||
|
|
@ -21,14 +19,12 @@ export interface userStateTypes {
|
|||
|
||||
const useLoginStore = defineStore('user', {
|
||||
state: (): userStateTypes => ({
|
||||
userType: 1,
|
||||
// userInfo: null,
|
||||
token: '',
|
||||
userType: 1, // 1 系统操作者 2 对话用户
|
||||
userInfo: null,
|
||||
version: '',
|
||||
userAccessToken: '',
|
||||
XPACK_LICENSE_IS_VALID: false,
|
||||
isXPack: false,
|
||||
themeInfo: null
|
||||
themeInfo: null,
|
||||
}),
|
||||
actions: {
|
||||
getLanguage() {
|
||||
|
|
@ -36,62 +32,17 @@ const useLoginStore = defineStore('user', {
|
|||
? localStorage.getItem('MaxKB-locale') || getBrowserLang()
|
||||
: sessionStorage.getItem('language') || getBrowserLang()
|
||||
},
|
||||
// showXpack() {
|
||||
// return this.isXPack
|
||||
// },
|
||||
isDefaultTheme() {
|
||||
return !this.themeInfo?.theme || this.themeInfo?.theme === '#3370FF'
|
||||
},
|
||||
// setTheme(data: any) {
|
||||
// const { changeTheme } = useElementPlusTheme(this.themeInfo?.theme)
|
||||
// changeTheme(data?.['theme'])
|
||||
// this.themeInfo = cloneDeep(data)
|
||||
// },
|
||||
// isExpire() {
|
||||
// return this.isXPack && !this.XPACK_LICENSE_IS_VALID
|
||||
// },
|
||||
// isEnterprise() {
|
||||
// return this.isXPack && this.XPACK_LICENSE_IS_VALID
|
||||
// },
|
||||
// getToken(): String | null {
|
||||
// if (this.token) {
|
||||
// return this.token
|
||||
// }
|
||||
// return this.userType === 1 ? localStorage.getItem('token') : this.getAccessToken()
|
||||
// },
|
||||
// getAccessToken() {
|
||||
// const token = sessionStorage.getItem(`${this.userAccessToken}-accessToken`)
|
||||
// if (token) {
|
||||
// return token
|
||||
// }
|
||||
// const local_token = localStorage.getItem(`${token}-accessToken`)
|
||||
// if (local_token) {
|
||||
// return local_token
|
||||
// }
|
||||
// return localStorage.getItem(`accessToken`)
|
||||
// },
|
||||
|
||||
// getPermissions() {
|
||||
// if (this.userInfo) {
|
||||
// return this.isXPack && this.XPACK_LICENSE_IS_VALID
|
||||
// ? [...this.userInfo?.permissions, 'x-pack']
|
||||
// : this.userInfo?.permissions
|
||||
// } else {
|
||||
// return []
|
||||
// }
|
||||
// },
|
||||
// getRole() {
|
||||
// if (this.userInfo) {
|
||||
// return this.userInfo?.role
|
||||
// } else {
|
||||
// return ''
|
||||
// }
|
||||
// },
|
||||
// changeUserType(num: number, token?: string) {
|
||||
// this.userType = num
|
||||
// this.userAccessToken = token
|
||||
// },
|
||||
|
||||
async profile() {
|
||||
return UserApi.getUserProfile().then((ok: { data: User }) => {
|
||||
this.userInfo = ok.data
|
||||
useLocalStorage<string>(localeConfigKey, 'en-US').value =
|
||||
ok.data?.language || this.getLanguage()
|
||||
// return this.asyncGetProfile()
|
||||
})
|
||||
},
|
||||
// async asyncGetProfile() {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// UserApi.getProfile()
|
||||
|
|
@ -115,6 +66,43 @@ const useLoginStore = defineStore('user', {
|
|||
// })
|
||||
// },
|
||||
|
||||
getPermissions() {
|
||||
if (this.userInfo) {
|
||||
return this.isXPack && this.XPACK_LICENSE_IS_VALID
|
||||
? [...this.userInfo?.permissions, 'x-pack']
|
||||
: this.userInfo?.permissions
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
getRole() {
|
||||
if (this.userInfo) {
|
||||
return this.userInfo?.role
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
// showXpack() {
|
||||
// return this.isXPack
|
||||
// },
|
||||
|
||||
// setTheme(data: any) {
|
||||
// const { changeTheme } = useElementPlusTheme(this.themeInfo?.theme)
|
||||
// changeTheme(data?.['theme'])
|
||||
// this.themeInfo = cloneDeep(data)
|
||||
// },
|
||||
// isExpire() {
|
||||
// return this.isXPack && !this.XPACK_LICENSE_IS_VALID
|
||||
// },
|
||||
// isEnterprise() {
|
||||
// return this.isXPack && this.XPACK_LICENSE_IS_VALID
|
||||
// },
|
||||
|
||||
// changeUserType(num: number, token?: string) {
|
||||
// this.userType = num
|
||||
// this.userAccessToken = token
|
||||
// },
|
||||
|
||||
// async theme(loading?: Ref<boolean>) {
|
||||
// return await ThemeApi.getThemeInfo(loading).then((ok) => {
|
||||
// this.setTheme(ok.data)
|
||||
|
|
@ -126,21 +114,6 @@ const useLoginStore = defineStore('user', {
|
|||
// })
|
||||
// },
|
||||
|
||||
// async profile() {
|
||||
// return UserApi.profile().then(async (ok) => {
|
||||
// this.userInfo = ok.data
|
||||
// useLocalStorage(localeConfigKey, 'en-US').value = ok.data?.language || this.getLanguage()
|
||||
// return this.asyncGetProfile()
|
||||
// })
|
||||
// },
|
||||
|
||||
// async login(auth_type: string, username: string, password: string) {
|
||||
// return UserApi.login(auth_type, { username, password }).then((ok) => {
|
||||
// this.token = ok.data
|
||||
// localStorage.setItem('token', ok.data)
|
||||
// return this.profile()
|
||||
// })
|
||||
// },
|
||||
// async dingCallback(code: string) {
|
||||
// return UserApi.getDingCallback(code).then((ok) => {
|
||||
// this.token = ok.data
|
||||
|
|
@ -204,7 +177,7 @@ const useLoginStore = defineStore('user', {
|
|||
// })
|
||||
// })
|
||||
// }
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export default useLoginStore
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@
|
|||
@use './element-plus.scss';
|
||||
@use './variables.scss';
|
||||
@use './app.scss';
|
||||
@import 'nprogress/nprogress.css';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
import { t } from '@/locales'
|
||||
|
||||
export const MsgSuccess = (message: string) => {
|
||||
ElMessage.success({
|
||||
message: message,
|
||||
type: 'success',
|
||||
showClose: true,
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
|
||||
export const MsgInfo = (message: string) => {
|
||||
ElMessage.info({
|
||||
message: message,
|
||||
type: 'info',
|
||||
showClose: true,
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
|
||||
export const MsgWarning = (message: string) => {
|
||||
ElMessage.warning({
|
||||
message: message,
|
||||
type: 'warning',
|
||||
showClose: true,
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
|
||||
export const MsgError = (message: string) => {
|
||||
ElMessage.error({
|
||||
message: message,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
|
||||
export const MsgAlert = (title: string, description: string, options?: any) => {
|
||||
const defaultOptions: Object = {
|
||||
confirmButtonText: t('common.confirm'),
|
||||
...options
|
||||
}
|
||||
return ElMessageBox.alert(description, title, defaultOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除知识库
|
||||
* @param 参数 message: {title, description,type}
|
||||
*/
|
||||
|
||||
export const MsgConfirm = (title: string, description: string, options?: any) => {
|
||||
const defaultOptions: Object = {
|
||||
showCancelButton: true,
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
...options
|
||||
}
|
||||
return ElMessageBox.confirm(description, title, defaultOptions)
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import useStore from '@/stores';
|
||||
import { Role, Permission, ComplexPermission } from '@/utils/permission/type'
|
||||
/**
|
||||
* 是否包含当前权限
|
||||
* @param permission 当前权限
|
||||
* @returns True 包含 false 不包含
|
||||
*/
|
||||
const hasPermissionChild = (permission: Role | string | Permission | ComplexPermission) => {
|
||||
const { user } = useStore();
|
||||
const permissions = user.getPermissions()
|
||||
const role = user.getRole()
|
||||
if (!permission) {
|
||||
return true
|
||||
}
|
||||
if (permission instanceof Role) {
|
||||
return role === permission.role
|
||||
}
|
||||
if (permission instanceof Permission) {
|
||||
return permissions.includes(permission.permission)
|
||||
}
|
||||
if (permission instanceof ComplexPermission) {
|
||||
const permissionOk = permission.permissionList.some((p) => permissions.includes(p))
|
||||
const roleOk = permission.roleList.includes(role)
|
||||
return permission.compare === 'AND' ? permissionOk && roleOk : permissionOk || roleOk
|
||||
}
|
||||
if (typeof permission === 'string') {
|
||||
return permissions.includes(permission)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
/**
|
||||
* 判断是否有角色和权限
|
||||
* @param role 角色
|
||||
* @param permissions 权限
|
||||
* @param requiredPermissions 权限
|
||||
* @returns
|
||||
*/
|
||||
export const hasPermission = (
|
||||
permission:
|
||||
| Array<Role | string | Permission | ComplexPermission>
|
||||
| Role
|
||||
| string
|
||||
| Permission
|
||||
| ComplexPermission,
|
||||
compare: 'OR' | 'AND'
|
||||
): boolean => {
|
||||
if (permission instanceof Array) {
|
||||
return compare === 'OR'
|
||||
? permission.some((p) => hasPermissionChild(p))
|
||||
: permission.every((p) => hasPermissionChild(p))
|
||||
} else {
|
||||
return hasPermissionChild(permission)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* 角色对象
|
||||
*/
|
||||
export class Role {
|
||||
role: string
|
||||
|
||||
constructor(role: string) {
|
||||
this.role = role
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 权限对象
|
||||
*/
|
||||
export class Permission {
|
||||
permission: string
|
||||
|
||||
constructor(permission: string) {
|
||||
this.permission = permission
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 复杂权限对象
|
||||
*/
|
||||
export class ComplexPermission {
|
||||
roleList: Array<string>
|
||||
|
||||
permissionList: Array<string>
|
||||
|
||||
compare: 'OR' | 'AND'
|
||||
|
||||
constructor(roleList: Array<string>, permissionList: Array<string>, compare: 'OR' | 'AND') {
|
||||
this.roleList = roleList
|
||||
this.permissionList = permissionList
|
||||
this.compare = compare
|
||||
}
|
||||
}
|
||||
|
|
@ -2,27 +2,27 @@ import { t } from '@/locales'
|
|||
|
||||
export const themeList = [
|
||||
{
|
||||
label: t('views.system.theme.default'),
|
||||
label: t('theme.default'),
|
||||
value: '#3370FF',
|
||||
loginBackground: 'default',
|
||||
},
|
||||
{
|
||||
label: t('views.system.theme.orange'),
|
||||
label: t('theme.orange'),
|
||||
value: '#FF8800',
|
||||
loginBackground: 'orange',
|
||||
},
|
||||
{
|
||||
label: t('views.system.theme.green'),
|
||||
label: t('theme.green'),
|
||||
value: '#00B69D',
|
||||
loginBackground: 'green',
|
||||
},
|
||||
{
|
||||
label: t('views.system.theme.purple'),
|
||||
label: t('theme.purple'),
|
||||
value: '#7F3BF5',
|
||||
loginBackground: 'purple',
|
||||
},
|
||||
{
|
||||
label: t('views.system.theme.red'),
|
||||
label: t('theme.red'),
|
||||
value: '#F01D94',
|
||||
loginBackground: 'red',
|
||||
},
|
||||
|
|
@ -38,7 +38,7 @@ export const defaultSetting = {
|
|||
loginLogo: '',
|
||||
loginImage: '',
|
||||
title: 'MaxKB',
|
||||
slogan: t('views.system.theme.defaultSlogan'),
|
||||
slogan: t('theme.defaultSlogan'),
|
||||
}
|
||||
|
||||
export const defaultPlatformSetting = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<login-layout>
|
||||
<LoginContainer :subTitle="$t('views.system.theme.defaultSlogan')">
|
||||
<LoginContainer :subTitle="$t('theme.defaultSlogan')">
|
||||
<h2 class="mb-24">{{ $t('views.login.resetPassword') }}</h2>
|
||||
<el-form
|
||||
class="reset-password-form"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<login-layout>
|
||||
<LoginContainer :subTitle="$t('views.system.theme.defaultSlogan')">
|
||||
<LoginContainer :subTitle="$t('theme.defaultSlogan')">
|
||||
<h2 class="mb-24">{{ $t('views.login.resetPassword') }}</h2>
|
||||
<el-form
|
||||
class="reset-password-form"
|
||||
|
|
|
|||
|
|
@ -1,172 +0,0 @@
|
|||
<template>
|
||||
<div class="VerifyCode">
|
||||
<canvas
|
||||
id="VerifyCode-canvas"
|
||||
:width="props.contentWidth"
|
||||
:height="props.contentHeight"
|
||||
@click="refreshCode"
|
||||
></canvas>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, watch, computed } from 'vue'
|
||||
const props = defineProps({
|
||||
code: {
|
||||
type: String,
|
||||
default: '1234',
|
||||
},
|
||||
fontSizeMin: {
|
||||
type: Number,
|
||||
default: 25,
|
||||
},
|
||||
fontSizeMax: {
|
||||
type: Number,
|
||||
default: 35,
|
||||
},
|
||||
backgroundColorMin: {
|
||||
type: Number,
|
||||
default: 255,
|
||||
},
|
||||
backgroundColorMax: {
|
||||
type: Number,
|
||||
default: 255,
|
||||
},
|
||||
colorMin: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
colorMax: {
|
||||
type: Number,
|
||||
default: 160,
|
||||
},
|
||||
lineColorMin: {
|
||||
type: Number,
|
||||
default: 40,
|
||||
},
|
||||
lineColorMax: {
|
||||
type: Number,
|
||||
default: 180,
|
||||
},
|
||||
dotColorMin: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
dotColorMax: {
|
||||
type: Number,
|
||||
default: 255,
|
||||
},
|
||||
contentWidth: {
|
||||
type: Number,
|
||||
default: 112,
|
||||
},
|
||||
contentHeight: {
|
||||
type: Number,
|
||||
default: 40,
|
||||
},
|
||||
})
|
||||
|
||||
//验证码
|
||||
const emit = defineEmits(['update:code'])
|
||||
const verifyCode = computed({
|
||||
get: () => {
|
||||
return props.code
|
||||
},
|
||||
set: (data) => {
|
||||
emit('update:code', data)
|
||||
},
|
||||
})
|
||||
|
||||
// 生成校验码
|
||||
const makeCode = (len = 4) => {
|
||||
let code = ''
|
||||
const codeLength = len
|
||||
const identifyCodes = '123456789abcdefjhijkinpqrsduvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
|
||||
for (let i = 0; i < codeLength; i++) {
|
||||
code += identifyCodes[randomNum(0, identifyCodes.length)]
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
// 生成一个随机数
|
||||
const randomNum = (min = 0, max: number) => Math.floor(Math.random() * (max - min)) + min
|
||||
|
||||
// 生成一个随机的颜色
|
||||
function randomColor(min: number, max: number) {
|
||||
let r = randomNum(min, max)
|
||||
let g = randomNum(min, max)
|
||||
let b = randomNum(min, max)
|
||||
return 'rgb(' + r + ',' + g + ',' + b + ')'
|
||||
}
|
||||
|
||||
// 绘制干扰线
|
||||
const drawLine = (ctx: CanvasRenderingContext2D) => {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
ctx.strokeStyle = randomColor(props.lineColorMin, props.lineColorMax)
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight))
|
||||
ctx.lineTo(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight))
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
//在画布上显示数据
|
||||
const drawText = (ctx: CanvasRenderingContext2D, txt: string, i: number) => {
|
||||
ctx.fillStyle = randomColor(props.colorMin, props.colorMax)
|
||||
ctx.font = randomNum(props.fontSizeMin, props.fontSizeMax) + 'px SimHei'
|
||||
let x = (i + 1) * (props.contentWidth / (txt.length + 1))
|
||||
let y = randomNum(props.fontSizeMax, props.contentHeight - 5)
|
||||
var deg = randomNum(-45, 45)
|
||||
// 修改坐标原点和旋转角度
|
||||
ctx.translate(x, y)
|
||||
ctx.rotate((deg * Math.PI) / 180)
|
||||
ctx.fillText(txt[i], 0, 0)
|
||||
// 恢复坐标原点和旋转角度
|
||||
ctx.rotate((-deg * Math.PI) / 180)
|
||||
ctx.translate(-x, -y)
|
||||
}
|
||||
// 绘制干扰点
|
||||
const drawDot = (ctx: CanvasRenderingContext2D) => {
|
||||
for (let i = 0; i < 80; i++) {
|
||||
ctx.fillStyle = randomColor(0, 255)
|
||||
ctx.beginPath()
|
||||
ctx.arc(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight), 1, 0, 2 * Math.PI)
|
||||
ctx.fill()
|
||||
}
|
||||
}
|
||||
//画图
|
||||
const drawPic = () => {
|
||||
let canvas = document.getElementById('VerifyCode-canvas') as HTMLCanvasElement
|
||||
if (!canvas) {
|
||||
return
|
||||
}
|
||||
let ctx = canvas.getContext('2d') as CanvasRenderingContext2D
|
||||
ctx.textBaseline = 'bottom'
|
||||
// 绘制背景
|
||||
ctx.fillStyle = randomColor(props.backgroundColorMin, props.backgroundColorMax)
|
||||
ctx.fillRect(0, 0, props.contentWidth, props.contentHeight)
|
||||
// 绘制文字
|
||||
for (let i = 0; i < verifyCode.value.length; i++) {
|
||||
drawText(ctx, verifyCode.value, i)
|
||||
}
|
||||
drawLine(ctx)
|
||||
drawDot(ctx)
|
||||
}
|
||||
|
||||
// 重置验证码
|
||||
const refreshCode = () => {
|
||||
emit('update:code', makeCode())
|
||||
drawPic()
|
||||
}
|
||||
|
||||
// defineExpose({ refreshCode });
|
||||
|
||||
//组件挂载
|
||||
onMounted(() => {
|
||||
drawPic()
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.VerifyCode {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<login-layout v-if="!loading" v-loading="loading">
|
||||
<LoginContainer :subTitle="user.themeInfo?.slogan || $t('views.system.theme.defaultSlogan')">
|
||||
<LoginContainer :subTitle="user.themeInfo?.slogan || $t('theme.defaultSlogan')">
|
||||
<h2 class="mb-24">{{ $t('views.login.title') }}</h2>
|
||||
<div>
|
||||
<el-form
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
size="large"
|
||||
class="input-item"
|
||||
v-model="loginForm.username"
|
||||
:placeholder="$t('views.user.userForm.form.username.placeholder')"
|
||||
:placeholder="$t('views.login.loginForm.username.placeholder')"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
|
@ -28,36 +28,41 @@
|
|||
size="large"
|
||||
class="input-item"
|
||||
v-model="loginForm.password"
|
||||
:placeholder="$t('views.user.userForm.form.password.placeholder')"
|
||||
:placeholder="$t('views.login.loginForm.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mb-24">
|
||||
<el-form-item prop="code">
|
||||
<el-form-item prop="captcha">
|
||||
<div class="flex-between w-full">
|
||||
<el-input
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="loginForm.code"
|
||||
placeholder="请输入验证码"
|
||||
v-model="loginForm.captcha"
|
||||
:placeholder="$t('views.login.loginForm.captcha.placeholder')"
|
||||
>
|
||||
</el-input>
|
||||
<VerifyCode v-model:code="identifyCode" />
|
||||
|
||||
<img :src="identifyCode" alt="" height="40" class="ml-8 cursor" @click="makeCode" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<el-button size="large" type="primary" class="w-full" @click="login"
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
class="w-full"
|
||||
@click="loginHandle"
|
||||
:loading="loading"
|
||||
>
|
||||
>{{ $t('views.login.buttons.login') }}
|
||||
</el-button>
|
||||
<div class="operate-container flex-between mt-12">
|
||||
<!-- <el-button class="register" @click="router.push('/register')" link type="primary">
|
||||
注册
|
||||
</el-button> -->
|
||||
<el-button
|
||||
:loading="loading"
|
||||
class="forgot-password"
|
||||
@click="router.push('/forgot_password')"
|
||||
link
|
||||
|
|
@ -77,67 +82,64 @@ import type { FormInstance, FormRules } from 'element-plus'
|
|||
import type { LoginRequest } from '@/api/type/login'
|
||||
import LoginContainer from '@/views/login/components/LoginContainer.vue'
|
||||
import LoginLayout from '@/views/login/components/LoginLayout.vue'
|
||||
import VerifyCode from './components/VerifyCode.vue'
|
||||
import loginApi from '@/api/user/login'
|
||||
import { t, getBrowserLang } from '@/locales'
|
||||
import useStore from '@/stores'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const router = useRouter()
|
||||
const { user } = useStore()
|
||||
// const { locale } = useI18n({ useScope: 'global' })
|
||||
const { login, user } = useStore()
|
||||
const { locale } = useI18n({ useScope: 'global' })
|
||||
const loading = ref<boolean>(false)
|
||||
const identifyCode = ref<string>('1234')
|
||||
|
||||
const identifyCode = ref<string>('')
|
||||
|
||||
const loginFormRef = ref<FormInstance>()
|
||||
const loginForm = ref<LoginRequest>({
|
||||
username: '',
|
||||
password: '',
|
||||
code: '',
|
||||
captcha: '',
|
||||
})
|
||||
|
||||
const rules = ref<FormRules<LoginRequest>>({
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.user.userForm.form.username.requiredMessage'),
|
||||
message: t('views.login.loginForm.username.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.user.userForm.form.password.requiredMessage'),
|
||||
message: t('views.login.loginForm.password.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
captcha: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.login.loginForm.captcha.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// const modeList = ref<string[]>([''])
|
||||
// const QrList = ref<any[]>([''])
|
||||
// const loginMode = ref('')
|
||||
// const showQrCodeTab = ref(false)
|
||||
|
||||
// interface qrOption {
|
||||
// key: string
|
||||
// value: string
|
||||
// }
|
||||
|
||||
// const orgOptions = ref<qrOption[]>([])
|
||||
|
||||
const login = () => {
|
||||
// loginFormRef.value?.validate().then(() => {
|
||||
// loading.value = true
|
||||
// user
|
||||
// .login(loginMode.value, loginForm.value.username, loginForm.value.password)
|
||||
// .then(() => {
|
||||
// locale.value = localStorage.getItem('MaxKB-locale') || getBrowserLang() || 'en-US'
|
||||
// router.push({ name: 'home' })
|
||||
// })
|
||||
// .finally(() => (loading.value = false))
|
||||
// })
|
||||
const loginHandle = () => {
|
||||
loginFormRef.value?.validate().then(() => {
|
||||
login.asyncLogin(loginForm.value, loading).then(() => {
|
||||
locale.value = localStorage.getItem('MaxKB-locale') || getBrowserLang() || 'en-US'
|
||||
router.push({ name: 'home' })
|
||||
})
|
||||
})
|
||||
}
|
||||
function makeCode() {
|
||||
loginApi.getCaptcha().then((res: any) => {
|
||||
identifyCode.value = res.data.captcha
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
// loading.value = true
|
||||
makeCode()
|
||||
})
|
||||
|
||||
onMounted(() => {})
|
||||
|
|
|
|||
Loading…
Reference in New Issue