Desktop version has added a llm configuration page and a general configuration page

This commit is contained in:
aylvn 2025-03-18 22:20:37 +08:00
parent 2d507c0bcf
commit da607e31b2
23 changed files with 385 additions and 198 deletions

1
.gitignore vendored
View File

@ -181,4 +181,3 @@ workspace/
# Private Config
config/config.toml

View File

@ -69,7 +69,3 @@ To build the application:
wails build
The built application will be located in the projects dist directory.

View File

@ -69,7 +69,3 @@ nodejs官网安装: https://nodejs.org/en
wails build
构建好的应用在项目dist目录下

View File

@ -10,4 +10,3 @@
<script src="./src/main.js" type="module"></script>
</body>
</html>

View File

@ -1,16 +1,16 @@
import utils from '@/assets/js/utils'
import { ReadAll } from '@/../wailsjs/go/main/App.js'
// 临时缓存文件信息
// Temporarily cache file information
function cache(fileObj, $event) {
console.log('cache fileObj start:', fileObj, $event.target, $event.dataTransfer)
console.log('typeof fileObj:', Array.isArray(fileObj))
// 如果fileObj是数组,创建一个新的元素,追加到数组
// event.target.files和event.dataTransfer.files是JavaScript中与文件上传和拖放相关的事件属性。
// event.target.files这个属性是在HTML的文件输入元素<input type="file">)上使用时,
// 当用户选择文件并触发change事件时可以通过event.target.files获取到用户选择的文件列表。
// event.dataTransfer.files:这个属性是在用户拖放文件到一个元素上时,
// 可以通过event.dataTransfer.files获取到拖放的文件列表。
// If fileObj is an array, create a new element and append to the array
// event.target.files and event.dataTransfer.files are event properties in JavaScript related to file upload and drag-and-drop.
// event.target.files: This property is used with HTML file input elements (<input type="file">),
// When the user selects a file and triggers the change event, event.target.files can be used to get the list of files selected by the user.
// event.dataTransfer.files: This property is used when the user drags and drops files onto an element,
// event.dataTransfer.files can be used to get the list of dropped files.
console.log('$event:', $event, $event.type)
let files
if ($event.type == 'change') {
@ -18,7 +18,7 @@ function cache(fileObj, $event) {
} else if ($event.type == 'drop') {
files = $event.dataTransfer.files
} else {
console.error("无法识别的事件")
console.error("Unrecognized event")
return
}
const file = files[0]
@ -35,19 +35,19 @@ function cache(fileObj, $event) {
fileInfo.fileName = file.name
console.log('cache fileObj end:', fileInfo)
if (Array.isArray(fileObj)) {
// 操作成功后追加到数组末尾
// Append to the end of the array after successful operation
fileObj.push(fileInfo)
}
if ($event.type == 'change') {
// 解决选择相同的文件 不触发change事件的问题,放在最后清理
// Solve the problem of selecting the same file not triggering the change event, clean up at the end
$event.target.value = null
}
}
// 上传文件
// Upload file
async function upload(fileObj) {
console.log("准备开始上传文件!", fileObj, fileObj.file, fileObj.fileId)
// 当前地址
console.log("Ready to start uploading file!", fileObj, fileObj.file, fileObj.fileId)
// Current address
if (utils.isNull(fileObj.file)) {
if (utils.notNull(fileObj.fileId) && fileObj.remark != fileObj.remarkUpd) {
let remark = null
@ -58,7 +58,7 @@ async function upload(fileObj) {
}
return
}
console.log("开始上传文件!", fileObj, fileObj.file, fileObj.fileId)
console.log("Start uploading file!", fileObj, fileObj.file, fileObj.fileId)
const url = '/common/file/upload'
const formData = new FormData()
formData.append('file', fileObj.file)
@ -73,21 +73,21 @@ async function upload(fileObj) {
}
})
Object.assign(fileObj, data)
console.log("文件同步上传处理完毕", fileObj)
console.log("File upload completed", fileObj)
return fileObj
}
// 更新文件备注
// Update file remark
async function updRemark(fileId, remarkUpd) {
const param = {
fileId: fileId,
remark: remarkUpd
}
await utils.awaitPost('/common/file/updRemark', param)
console.log("更新文件备注成功")
console.log("File remark updated successfully")
}
// 批量上传文件
// Batch upload files
async function uploads(fileObjs) {
if (utils.isEmpty(fileObjs)) {
return
@ -95,16 +95,16 @@ async function uploads(fileObjs) {
for (let index in fileObjs) {
console.log('fileObjs[index]:', fileObjs, index, fileObjs.length, fileObjs[index])
await upload(fileObjs[index])
console.log("uploads index:", index, "上传文件完毕", fileObjs[index])
console.log("uploads index:", index, "File upload completed", fileObjs[index])
}
}
// 上传文件(onChange时)
// Upload file (onChange)
function upOnChg(fileObj, $event) {
const file = $event.target.files[0] || $event.dataTransfer.files[0]
// 当前地址
// Current address
let URL = window.URL || window.webkitURL
// 转成 blob地址
// Convert to blob address
fileObj.fileUrl = URL.createObjectURL(file)
const url = '/common/file/upload'
const formData = new FormData()
@ -115,7 +115,7 @@ function upOnChg(fileObj, $event) {
'Content-Type': 'multipart/form-data'
}
}).then((data) => {
console.log("文件上传结果:", data)
console.log("File upload result:", data)
Object.assign(fileObj, data)
fileObj.remarkUpd = data.remark
})
@ -147,7 +147,7 @@ function trans(javaFile, jsFile) {
if (jsFile == undefined || jsFile == null) {
return
}
// 如果是数组,先清空数组
// If it is an array, clear the array first
if (jsFile instanceof Array) {
jsFile.splice(0, jsFile.length)
} else {
@ -157,7 +157,7 @@ function trans(javaFile, jsFile) {
if (javaFile == undefined || javaFile == null) {
return
}
// 数组类型
// Array type
if (jsFile instanceof Array) {
for (let java of javaFile) {
const js = {}
@ -166,14 +166,14 @@ function trans(javaFile, jsFile) {
jsFile.push(js)
}
} else {
// 对象类型
console.log("对象类型", jsFile instanceof Array)
// Object type
console.log("Object type", jsFile instanceof Array)
javaFile.remarkUpd = javaFile.remark
Object.assign(jsFile, javaFile)
}
}
// 从Comps中收集fileId
// Collect fileId from Comps
function fileIds(fileList) {
return fileList.map(comp => comp.fileId).join(',')
}
@ -183,24 +183,24 @@ function readAll(filePath) {
}
export default {
// onChange时缓存
// Cache on onChange
cache,
// 上传文件
// Upload file
upload,
// 上传文件
// Upload files
uploads,
// 上传文件
// Upload file
upOnChg,
// onChange时上传
// Upload on onChange
upOnChg,
// 添加到组件列表
// Add to component list
add,
// 从组件列表中删除组件
// Delete component from component list
del,
// 文件Java对象与js对象转换
// Convert between Java object and js object
trans,
// 从Comps中收集fileId
// Collect fileId from Comps
fileIds,
// 读取文件
// Read file
readAll
}

View File

@ -1,7 +1,7 @@
import { useEventListener } from '@vueuse/core'
/*
* 显示页面遮罩
* Show page shade
*/
export const showShade = function (closeCallBack) {
const className = 'shade'
@ -13,7 +13,7 @@ export const showShade = function (closeCallBack) {
}
/*
* 隐藏页面遮罩
* Hide page shade
*/
export const closeShade = function (closeCallBack = () => { }) {
const shadeEl = document.querySelector('.layout-shade')

View File

@ -3,13 +3,13 @@ import { ElMessage } from 'element-plus'
import { Greet } from '@/../wailsjs/go/main/App.js'
/** axios start */
// 创建 axios 实例
// Create axios instance
const $axios = axios.create({
baseURL: "api",
timeout: 12000
})
// 请求拦截器
// Request interceptor
$axios.interceptors.request.use(
(config) => {
config.headers["token"] = ''
@ -27,24 +27,24 @@ $axios.interceptors.request.use(
}
)
// 响应拦截器
// Response interceptor
$axios.interceptors.response.use(
(response) => {
// console.log("response:", response)
if (response.status == 200) {
return response.data
} else {
pop("请求错误:" + response.status)
pop("Request error:" + response.status)
}
},
(error) => {
console.log("error:" + JSON.stringify(error))
if (error.response == undefined || error.response == null) {
pop("未知请求错误!")
pop("Unknown request error!")
} else if (error.response.status == 500) {
pop("请求后台服务异常,请稍后重试!")
pop("Backend service error, please try again later!")
} else {
pop("请求错误:" + error)
pop("Request error:" + error)
}
return Promise.reject(error)
}
@ -75,7 +75,7 @@ async function awaitDel(url, param) {
}
/**
* demo 调用 go 接口
* Demo call to go interface
*/
function greet(name) {
return Greet(name).then(resp => {
@ -85,78 +85,78 @@ function greet(name) {
}
/**
* 判断对象为空
* Check if object is null
*/
function isNull(obj) {
return obj == undefined || obj == null
}
/**
* 判断对象非空
* Check if object is not null
*/
function notNull(obj) {
return obj != undefined && obj != null
}
/**
* 判断空字符串
* Check if string is blank
*/
function isBlank(str) {
return str == undefined || str == null || /^s*$/.test(str)
}
/**
* 判断不为空字符串
* Check if string is not blank
*/
function notBlank(str) {
return !isBlank(str)
}
/**
* 判断数组为空
* Check if array is empty
*/
function isEmpty(arr) {
return arr == undefined || arr == null || (arr instanceof Array && arr.length == 0)
}
/**
* 判断数组非空
* Check if array is not empty
*/
function notEmpty(arr) {
return arr != undefined && arr != null && arr instanceof Array && arr.length > 0
}
/**
* 判断对象为true
* Check if object is true
*/
function isTrue(obj) {
return obj == true || obj == 'true'
}
/**
* 判断对象为false
* Check if object is false
*/
function isFalse(obj) {
return !isTrue(obj)
}
/**
* @param {string} str - 要搜索的字符串
* @param {string} char - 要查找的字符
* @returns {number} - 字符在字符串中出现的次数
/** Get the count of a character in a string
* @param {string} str - The string to search
* @param {string} char - The character to find
* @returns {number} - The count of the character in the string
*/
function getCharCount(str, char) {
// 使用g表示整个字符串都要匹配
// Use g to match the entire string
var regex = new RegExp(char, 'g')
// match方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配
// match method can search for specified values in a string or find one or more matches of a regular expression
var result = str.match(regex)
var count = !result ? 0 : result.length
return count
}
/**
* 日期格式化
* 默认格式为yyyy-MM-dd HH:mm:ss
* Date format
* Default format is yyyy-MM-dd HH:mm:ss
*/
function dateFormat(date, format) {
if (date == undefined || date == null || date == '') {
@ -187,27 +187,27 @@ function dateFormat(date, format) {
}
/**
* 遍历对象中的日期,并进行格式化
* Traverse and format date properties in object
*/
function fomateDateProperty(obj) {
for (let i in obj) {
//遍历对象中的属性
// Traverse properties in object
if (obj[i] == null) {
continue
} else if (obj[i] instanceof Date) {
// 格式化为yyyy-MM-dd HH:mm:ss
// Format to yyyy-MM-dd HH:mm:ss
obj[i] = dateFormat(obj[i])
} else if (obj[i].constructor === Object) {
//如果发现该属性的值还是一个对象,再判空后进行迭代调用
// If the property value is still an object, check if it's empty and then iterate
if (Object.keys(obj[i]).length > 0) {
//判断对象上是否存在属性,如果为空对象则删除
// Check if the object has properties, delete if it's an empty object
fomateDateProperty(obj[i])
}
} else if (obj[i].constructor === Array) {
//对象值如果是数组,判断是否为空数组后进入数据遍历判空逻辑
// If the object value is an array, check if it's empty and then iterate
if (obj[i].length > 0) {
for (let j = 0; j < obj[i].length; j++) {
//遍历数组
// Traverse array
fomateDateProperty(obj[i][j])
}
}
@ -216,34 +216,34 @@ function fomateDateProperty(obj) {
}
// 遍历删除对象中的空值属性
// Traverse and delete null properties in object
function delNullProperty(obj) {
for (let i in obj) {
//遍历对象中的属性
// Traverse properties in object
if (obj[i] === undefined || obj[i] === null || obj[i] === "") {
//首先除去常规空数据用delete关键字
// First remove regular empty data using delete keyword
delete obj[i]
} else if (obj[i].constructor === Object) {
//如果发现该属性的值还是一个对象,再判空后进行迭代调用
// If the property value is still an object, check if it's empty and then iterate
if (Object.keys(obj[i]).length === 0) delete obj[i]
//判断对象上是否存在属性,如果为空对象则删除
// Check if the object has properties, delete if it's an empty object
delNullProperty(obj[i])
} else if (obj[i].constructor === Array) {
//对象值如果是数组,判断是否为空数组后进入数据遍历判空逻辑
// If the object value is an array, check if it's empty and then iterate
if (obj[i].length === 0) {
//如果数组为空则删除
// If the array is empty, delete it
delete obj[i]
} else {
for (let index = 0; index < obj[i].length; index++) {
//遍历数组
// Traverse array
if (obj[i][index] === undefined || obj[i][index] === null || obj[i][index] === "" || JSON.stringify(obj[i][index]) === "{}") {
obj[i].splice(index, 1)
//如果数组值为以上空值则修改数组长度,移除空值下标后续值依次提前
// If the array value is one of the above empty values, modify the array length, move subsequent values forward
index--
//由于数组当前下标内容已经被替换成下一个值,所以计数器需要自减以抵消之后的自增
// Since the current index content has been replaced by the next value, the counter needs to decrement to offset the subsequent increment
}
if (obj[i].constructor === Object) {
//如果发现数组值中有对象,则再次进入迭代
// If an object is found in the array value, iterate again
delNullProperty(obj[i])
}
}
@ -253,8 +253,8 @@ function delNullProperty(obj) {
}
/**
* 弹出消息框
* @param msg 消息内容
* Show message box
* @param msg Message content
* @param type
*/
function pop(msg, type) {
@ -263,12 +263,12 @@ function pop(msg, type) {
function popNoData(data) {
if (data == undefined || data == null || (data instanceof Array && data.length == 0)) {
ElMessage("暂无数据!")
ElMessage("No data!")
}
}
/**
* 当前时间字符串
* Current datetime string
*/
function nowDatetimeStr() {
const date = new Date()
@ -277,7 +277,7 @@ function nowDatetimeStr() {
}
/**
* 构建分页
* Build pagination
*/
function buildPage(source, target) {
target.pageNum = source.pageNum
@ -287,7 +287,7 @@ function buildPage(source, target) {
copyArray(source.list, target.list)
}
/**
* 清空数组
* Clear array
*/
function clearArray(arr) {
if (arr == undefined || arr == null || arr.length == 0) {
@ -296,7 +296,7 @@ function clearArray(arr) {
arr.splice(0, arr.length)
}
/**
* 清空属性
* Clear properties
*/
function clearProps(obj) {
if (obj == undefined || obj == null) {
@ -308,7 +308,7 @@ function clearProps(obj) {
}
/**
* 复制对象属性
* Copy object properties
*/
function copyProps(source, target) {
if (target == undefined || target == null) {
@ -322,13 +322,13 @@ function copyProps(source, target) {
}
}
/**
* 复制数组
* Copy array
*/
function copyArray(source, target) {
if (target == undefined || target == null) {
return
}
// 先清空数组
// Clear array first
if (target.length > 0) {
target.splice(0, target.length)
/* while (target.length > 0) {
@ -344,7 +344,7 @@ function copyArray(source, target) {
}
/**
* 发生变更的属性
* Changed properties
*/
function dfProps(origin, target) {
if (origin == undefined || origin == null || target == undefined || target == null) {
@ -361,7 +361,7 @@ function dfProps(origin, target) {
/**
* 是否存在不同属性
* Check if there are different properties
*/
function hasDfProps(origin, target) {
const df = dfProps(origin, target)
@ -374,7 +374,7 @@ function hasDfProps(origin, target) {
}
/**
* 所有字段为空
* All fields are empty
*/
function isAllPropsNull(target) {
if (target == undefined || target == null) {
@ -425,19 +425,19 @@ function colorByLabel(label) {
function descByLabel(label) {
if ('ADD' == label) {
return '新增'
return 'Add'
}
if ('UPD' == label) {
return '更新'
return 'Update'
}
if ('DEL' == label) {
return '删除'
return 'Delete'
}
return label
}
/**
* 重试调用
* Retry call
*/
function retry(method) {
const params = []
@ -450,7 +450,7 @@ function retry(method) {
}
/**
* 根据opts编码匹配中文
* Match Chinese label from opts encoding
*/
function resolveLabelFromOpts(keyOrVal, opts) {
if (isEmpty(opts)) {
@ -464,7 +464,7 @@ function resolveLabelFromOpts(keyOrVal, opts) {
return keyOrVal
}
/** 下划线转首字母小写驼峰 */
/** Convert underscore to camel case with first letter lowercase */
function underScoreToCamelCase(underscore) {
if (isNull(underscore) || !underscore.includes('_')) {
return underscore
@ -480,7 +480,7 @@ function underScoreToCamelCase(underscore) {
return words.join("")
}
/** 防抖函数 */
/** Debounce function */
function debounce(func, delay) {
let timer
return function () {
@ -494,6 +494,9 @@ function debounce(func, delay) {
}
}
/**
* Convert string to lines
*/
function stringToLines(str) {
if (str == undefined || str == null) {
return []
@ -503,42 +506,42 @@ function stringToLines(str) {
export default {
/**
* http请求 GET请求
* HTTP request GET
*/
get,
/**
* http请求, 异步等待 GET请求
* HTTP request, async await GET
*/
awaitGet,
/**
* http请求 POST请求
* HTTP request POST
*/
post,
/**
* http请求, 异步等待 POST请求
* HTTP request, async await POST
*/
awaitPost,
/**
* http请求 DELETE请求
* HTTP request DELETE
*/
del,
/**
* http请求, 异步等待 DELETE请求
* HTTP request, async await DELETE
*/
awaitDel,
/**
* 判断对象为空
* Check if object is null
*/
isNull,
/**
* 判断对象非空
* Check if object is not null
*/
notNull,
@ -547,12 +550,12 @@ export default {
notBlank,
/**
* 判断数组为空
* Check if array is empty
*/
isEmpty,
/**
* 判断数组非空
* Check if array is not empty
*/
notEmpty,
@ -563,64 +566,63 @@ export default {
getCharCount,
/**
* 弹出消息提示
* Show message popup
*/
pop,
/**
* 判定数据是否为空, 如果为空则提示暂无数据
* Check if data is empty, if empty show "No data" message
*/
popNoData,
/**
* 遍历删除对象中的空值属性
* Traverse and delete null properties in object
*/
delNullProperty,
/**
*
* 当前时间字符串
* Current datetime string
*/
nowDatetimeStr,
/**
* 构建分页
* Build pagination
*/
buildPage,
/**
* 清空数组
* Clear array
*/
clearArray,
/**
* 清空属性
* Clear properties
*/
clearProps,
/**
* 复制对象属性
* Copy object properties
*/
copyProps,
/**
* 复制数组
* Copy array
*/
copyArray,
/**
* 日期格式化
* 默认格式为yyyy-MM-dd HH:mm:ss
* Date format
* Default format is yyyy-MM-dd HH:mm:ss
*/
dateFormat,
/**
* 遍历对象中的日期,并进行格式化
* Traverse and format date properties in object
*/
fomateDateProperty,
/**
* 发生变更的属性
* Changed properties
*/
dfProps,
@ -633,7 +635,7 @@ export default {
descByLabel,
/**
* 重试调用
* Retry call
*/
retry,

View File

@ -1,15 +1,15 @@
import utils from '@/assets/js/utils'
/** 英文编码正则 */
/** English code regex */
const codeReg = /^[A-Za-z0-9_\-\.]+$/
/** 手机号正则 */
/** Mobile number regex */
const mobileReg = /^1[3456789]\d{9}$/
/** 大陆身份证正则 */
/** Mainland ID card regex */
const idNoReg = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/
/** email正则 */
/** Email regex */
const emailReg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
const commonValidator = (rule, value, callback) => {
@ -22,7 +22,7 @@ const commonValidator = (rule, value, callback) => {
const notBlankValidator = (rule, value, callback) => {
if (utils.isBlank(value)) {
callback(new Error('输入不能为空'))
callback(new Error('Input cannot be empty'))
} else {
callback()
}
@ -32,7 +32,7 @@ const nameValidator = (rule, value, callback) => {
if (utils.isBlank(value)) {
callback()
} else if (value.length > 50) {
callback(new Error('字符数不能超过50'))
callback(new Error('Character count cannot exceed 50'))
} else {
callback()
}
@ -42,7 +42,7 @@ const mobileValidator = (rule, value, callback) => {
if (utils.isNull(value)) {
callback()
} else if (!mobileReg.test(value)) {
callback(new Error('手机号格式错误'))
callback(new Error('Invalid mobile number format'))
} else {
callback()
}
@ -52,7 +52,7 @@ const idNoValidator = (rule, value, callback) => {
if (utils.isNull(value)) {
callback()
} else if (!idNoReg.test(value)) {
callback(new Error('手机号格式错误'))
callback(new Error('Invalid ID number format'))
} else {
callback()
}
@ -62,7 +62,7 @@ const emailValidator = (rule, value, callback) => {
if (utils.isNull(value)) {
callback()
} else if (!emailReg.test(value)) {
callback(new Error('手机号格式错误'))
callback(new Error('Invalid email format'))
} else {
callback()
}
@ -72,7 +72,7 @@ const codeValidator = (rule, value, callback) => {
if (utils.isBlank(value)) {
callback()
} else if (!codeReg.test(value)) {
callback(new Error('编码格式错误'))
callback(new Error('Invalid code format'))
} else {
callback()
}
@ -82,7 +82,7 @@ const intValidator = (rule, value, callback) => {
if (utils.isBlank(value)) {
callback()
} else if (!Number.isInteger(value)) {
callback(new Error('请输入整数'))
callback(new Error('Please enter an integer'))
} else {
callback()
}
@ -92,7 +92,7 @@ function validator() {
console.log("arguments:", arguments)
if (arguments.length <= 1) {
const type = arguments[0]
// 默认校验逻辑, 不含有特殊字符
// Default validation logic, no special characters
if (utils.isBlank(type)) {
return commonValidator
} else if (type == 'notBlank') {
@ -113,22 +113,22 @@ function validator() {
return commonValidator
}
}
// 复合校验器
// Complex validator
const complexValidator = (rule, value, callback) => {
for (let i = 0; i < arguments.length; i++) {
const typeStr = arguments[i]
if (typeStr == 'notBlank' && utils.isBlank(value)) {
callback(new Error('输入不能为空'))
callback(new Error('Input cannot be empty'))
break
} else if (typeStr == 'code' && !codeReg.test(value)) {
callback(new Error('编码格式错误'))
callback(new Error('Invalid code format'))
break
} else if (typeStr == 'int' && Number.isInteger(value)) {
callback(new Error('请输入整数'))
callback(new Error('Please enter an integer'))
break
}
}
// 兜底callback()只会触发一次
// Fallback callback() will only trigger once
callback()
}
return complexValidator
@ -138,62 +138,62 @@ export default {
username: (username) => {
if (typeof (username) == "undefined" || username == null) {
return "账号不能为空"
return "Username cannot be empty"
}
username = username.trim()
if (username.length < 4) {
return "账号字符不能小于4位"
return "Username must be at least 4 characters"
}
if (username.length > 20) {
return "账号字符不能大于20位"
return "Username cannot exceed 20 characters"
}
const reg = /^[A-Za-z0-9]+$/
if (!reg.test(username)) {
return "账号为必须为字母和数字"
return "Username must be letters and numbers only"
}
return null
},
password: (password) => {
if (typeof (password) == "undefined" || password == null) {
return "密码不能为空"
return "Password cannot be empty"
}
password = password.trim()
if (password.length < 4) {
return "密码字符不能小于4位"
return "Password must be at least 4 characters"
}
if (password.length > 20) {
return "密码字符不能大于20位"
return "Password cannot exceed 20 characters"
}
const reg = /^[A-Za-z0-9\.\-\_\+]+$/
if (!reg.test(password)) {
return "密码为必须为字母和数字或.-+_"
return "Password must be letters, numbers, or .-+_"
}
return null
},
email: (email) => {
if (typeof (email) == "undefined" || email == null) {
return "邮箱不能为空"
return "Email cannot be empty"
}
const reg = /^[A-Za-z0-9._%-]+@([A-Za-z0-9-]+\.)+[A-Za-z]{2,4}$/
if (!reg.test(email)) {
return "邮箱格式不正确"
return "Invalid email format"
}
return null
},
validCode: (validCode) => {
if (typeof (validCode) == "undefined" || validCode == null) {
return "验证码不能为空"
return "Verification code cannot be empty"
}
validCode = validCode.trim()
if (validCode.length != 6) {
return "验证码必须为6位"
return "Verification code must be 6 digits"
}
const reg = /^[A-Za-z0-9]{6}$/
if (!reg.test(validCode)) {
return "验证码格式不正确"
return "Invalid verification code format"
}
return null
},

View File

@ -37,16 +37,16 @@ export default defineConfig({
},
build: {
chunkSizeWarningLimit: 1500,
// 分解块,将大块分解成更小的块
// Split chunks, break large chunks into smaller ones
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
// 让每个插件都打包成独立的文件
// Let each plugin be packaged into an independent file
return id.toString().split('node_modules/')[1].split('/')[0].toString();
}
},
// 单位b, 合并较小模块
// Unit b, merge smaller modules
experimentalMinChunkSize: 10 * 1024,
}
},

View File

@ -35,6 +35,7 @@ export default {
promptInputPlaceHolder: "Please Input Task Prompt",
promptInput: "Prompt Input",
promptInputKw: "Prompt Input",
clearCache: "Clear Cache",
clearCacheSuccess: "Clear cache success",
openManusAgiTips: "The above content is generated by OpenManus for reference only",
taskStatus: {
@ -45,5 +46,8 @@ export default {
terminated: "Terminated",
},
newTask: "New Task",
readConfigSuccess: "Read config success",
readConfigFailed: "Read config failed",
baseConfig: "Base Settings",
serverConfig: "Server Config",
}

View File

@ -34,6 +34,7 @@ export default {
promptInputPlaceHolder: "请输入任务提示词",
promptInput: "提示词输入",
promptInputKw: "提示词关键字",
clearCache: "清理缓存",
clearCacheSuccess: "清理缓存成功",
openManusAgiTips: "以上内容由OpenManus生成, 仅供参考和借鉴",
taskStatus: {
@ -44,4 +45,8 @@ export default {
terminated: "终止",
},
newTask: "新任务",
readConfigSuccess: "读取配置成功",
readConfigFailed: "读取配置失败",
baseConfig: "基础设置",
serverConfig: "服务器配置",
}

View File

@ -52,4 +52,3 @@ app.provide('verify', verify)
/* app.provide('uuid', uuidv4) */
app.mount('#app')

View File

@ -3,33 +3,211 @@
<el-card>
<template #header>
<div class="title fxsb">
<div>基本信息</div>
<div>{{ t('baseConfig') }}</div>
</div>
</template>
<!-- Show Data -->
<div class="card-row-wrap" v-show="baseShow">
<div class="card-row-aline fxsb">
<el-text>{{ t('clearCache') }}:</el-text>
<el-button type="danger" class="mlr-10" @click="clearCache">{{ t('clearCache') }}</el-button>
</div>
</div>
</el-card>
<el-card>
<template #header>
<div class="title fxsb">
<div> {{ t('serverConfig') }}</div>
<div>
<el-link type="primary" class="no-select plr-6" @click="clearCache()">清理缓存</el-link>
<el-link type="primary" class="no-select plr-6" @click="toEdit('server')" v-show="serverShow">
{{ t('edit') }}
</el-link>
<el-link type="primary" class="no-select plr-6" @click="toShow('server')" v-show="serverEdit">
{{ t('cancel') }}
</el-link>
</div>
</div>
</template>
<!-- No Data -->
<div class="no-data" v-show="serverNoData">{{ t('noData') }}</div>
<!-- Show Data -->
<div class="card-row-wrap" v-show="serverShow">
<div class="card-row-item">
<el-text>host:</el-text>
<el-text>{{ serverConfig.host }}</el-text>
</div>
<div class="card-row-item">
<el-text>port:</el-text>
<el-text tag="p">{{ serverConfig.port }}</el-text>
</div>
</div>
<!-- Edit Module -->
<el-form ref="ruleFormRef" :model="serverConfigUpd" status-icon :rules="rules" v-show="serverEdit">
<div class="card-row-wrap">
<div class="card-row-item">
<el-text>host:</el-text>
<el-form-item prop="host">
<el-input v-model="serverConfigUpd.host" />
</el-form-item>
</div>
<div class="card-row-item">
<el-text>port:</el-text>
<el-form-item prop="port">
<el-input v-model="serverConfigUpd.port" />
</el-form-item>
</div>
<div class="card-row-aline fxc" v-show="serverEdit">
<el-button class="mlr-10" @click="toShow('server')">{{ t('cancel') }}</el-button>
<el-button type="primary" class="mlr-10" @click="submitForm">{{ t('submit') }}</el-button>
</div>
</div>
</el-form>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive, inject, onMounted } from 'vue'
import { ref, reactive, inject, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useConfig } from '@/store/config'
import { useI18n } from 'vue-i18n'
const utils = inject('utils')
const files = inject('files')
const verify = inject('verify')
const router = useRouter()
const config = useConfig()
const { t } = useI18n()
//
const viewModel = reactive({
base: 'show',
server: 'show',
})
function toShow(model) {
console.log("toShow:" + model)
viewModel[model] = 'show'
}
function toEdit(model) {
console.log("toEdit:" + model)
viewModel[model] = 'edit'
}
const baseShow = computed(() => {
return viewModel.base == 'show'
})
const baseEdit = computed(() => {
return viewModel.base == 'edit'
})
const baseNoData = computed(() => {
return baseShow && serverConfig.model == null
})
const serverShow = computed(() => {
return viewModel.server == 'show'
})
const serverEdit = computed(() => {
return viewModel.server == 'edit'
})
const readConfigSuccess = ref(false)
const serverNoData = computed(() => {
return serverShow && !readConfigSuccess.value
})
const serverConfig = reactive({
host: null,
port: null,
})
const serverConfigUpd = reactive({
host: null,
port: null,
})
function clearCache() {
config.$reset()
utils.pop(t('clearCacheSuccess'))
}
onMounted(() => {
// config/config.toml
files.readAll("@/../../config/config.toml").then((fileContent) => {
console.log("config/config.toml: ", fileContent)
if (utils.notBlank(fileContent)) {
readConfigSuccess.value = true
} else {
utils.pop(t('readConfigFailed'))
return
}
const lines = utils.stringToLines(fileContent)
// [server]
const serverStart = lines.findIndex((line) => {
return line.includes("[server]")
})
for (let i = serverStart + 1; i < lines.length; i++) {
console.log("line: ", lines[i])
//
if (lines[i].startsWith("[")) {
break
}
//
const line = lines[i]
const lineArr = line.split("=")
if (lineArr.length != 2) {
continue
}
const key = lineArr[0].trim()
const value = lineArr[1].trim()
serverConfig[key] = value
}
console.log("serverConfig read from file: ", serverConfig)
utils.copyProps(serverConfig, serverConfigUpd)
})
})
const submitForm = async () => {
try {
await ruleFormRef.value.validate();
if (!utils.hasDfProps(serverConfig, serverConfigUpd)) {
ElMessage.success('未发生更改!');
toShow('server')
return
}
ElMessage.success('验证通过,提交表单');
// update()
} catch (error) {
ElMessage.error('参数验证失败');
}
}
const rules = reactive({
host: [{ validator: verify.validator('notBlank'), trigger: 'blur' }],
port: [{ validator: verify.validator('notBlank'), trigger: 'blur' }],
api_key: [{ validator: verify.validator('notBlank'), trigger: 'blur' }],
max_tokens: [{ validator: verify.validator('notBlank'), trigger: 'blur' }],
temperature: [{ validator: verify.validator('notBlank'), trigger: 'blur' }],
})
</script>
<style scoped></style>

View File

@ -15,10 +15,10 @@
</div>
</template>
<!-- 展示模块-无数据 -->
<!-- No Data -->
<div class="no-data" v-show="baseNoData">{{ t('noData') }}</div>
<!-- 展示模块-有数据 -->
<!-- Show Data -->
<div class="card-row-wrap" v-show="baseShow">
<div class="card-row-item">
<el-text>model:</el-text>
@ -46,7 +46,7 @@
</div>
</div>
<!-- 编辑模块 -->
<!-- Edit Module -->
<el-form ref="ruleFormRef" :model="llmConfigUpd" status-icon :rules="rules" v-show="baseEdit">
<div class="card-row-wrap">
<div class="card-row-item">
@ -124,15 +124,17 @@ function toEdit(model) {
}
const baseShow = computed(() => {
return viewModel.base == 'show' || viewModel.base == 'showMore'
return viewModel.base == 'show'
})
const baseEdit = computed(() => {
return viewModel.base == 'edit'
})
const readConfigSuccess = ref(false)
const baseNoData = computed(() => {
return baseShow && llmConfig.model == null
return baseShow && !readConfigSuccess.value
})
const llmConfig = reactive({
@ -153,12 +155,19 @@ const llmConfigUpd = reactive({
function clearCache() {
config.$reset()
utils.pop(t('clearCacheSuccess'))
}
onMounted(() => {
// config/config.toml
files.readAll("@/../../config/config.toml").then((fileContent) => {
console.log("config/config.toml: ", fileContent)
if (utils.notBlank(fileContent)) {
readConfigSuccess.value = true
} else {
utils.pop(t('readConfigFailed'))
return
}
const lines = utils.stringToLines(fileContent)
// [llm]
@ -190,7 +199,7 @@ onMounted(() => {
const submitForm = async () => {
try {
await ruleFormRef.value.validate();
if (!utils.hasDfProps(designSchemeDtl, designSchemeUpd)) {
if (!utils.hasDfProps(llmConfig, llmConfigUpd)) {
ElMessage.success('未发生更改!');
toShow('base')
return

View File

@ -81,7 +81,7 @@ const viewModel = reactive({
})
const baseShow = computed(() => {
return viewModel.base == 'show' || viewModel.base == 'showMore'
return viewModel.base == 'show'
})
const baseNoData = computed(() => {

View File

@ -31,4 +31,3 @@ wails build
npm install axios
npm install qs
npm i --save-dev @types/qs

View File

@ -4,5 +4,6 @@ def factorial(n):
else:
return n * factorial(n - 1)
# Example usage
print(factorial(5))