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 # Private Config
config/config.toml config/config.toml

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -35,6 +35,7 @@ export default {
promptInputPlaceHolder: "Please Input Task Prompt", promptInputPlaceHolder: "Please Input Task Prompt",
promptInput: "Prompt Input", promptInput: "Prompt Input",
promptInputKw: "Prompt Input", promptInputKw: "Prompt Input",
clearCache: "Clear Cache",
clearCacheSuccess: "Clear cache success", clearCacheSuccess: "Clear cache success",
openManusAgiTips: "The above content is generated by OpenManus for reference only", openManusAgiTips: "The above content is generated by OpenManus for reference only",
taskStatus: { taskStatus: {
@ -45,5 +46,8 @@ export default {
terminated: "Terminated", terminated: "Terminated",
}, },
newTask: "New Task", 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: "请输入任务提示词", promptInputPlaceHolder: "请输入任务提示词",
promptInput: "提示词输入", promptInput: "提示词输入",
promptInputKw: "提示词关键字", promptInputKw: "提示词关键字",
clearCache: "清理缓存",
clearCacheSuccess: "清理缓存成功", clearCacheSuccess: "清理缓存成功",
openManusAgiTips: "以上内容由OpenManus生成, 仅供参考和借鉴", openManusAgiTips: "以上内容由OpenManus生成, 仅供参考和借鉴",
taskStatus: { taskStatus: {
@ -44,4 +45,8 @@ export default {
terminated: "终止", terminated: "终止",
}, },
newTask: "新任务", newTask: "新任务",
readConfigSuccess: "读取配置成功",
readConfigFailed: "读取配置失败",
baseConfig: "基础设置",
serverConfig: "服务器配置",
} }

View File

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

View File

@ -3,33 +3,211 @@
<el-card> <el-card>
<template #header> <template #header>
<div class="title fxsb"> <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> <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>
</div> </div>
</template> </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> </el-card>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, reactive, inject, onMounted } from 'vue' import { ref, reactive, inject, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useConfig } from '@/store/config' import { useConfig } from '@/store/config'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
const utils = inject('utils') const utils = inject('utils')
const files = inject('files')
const verify = inject('verify')
const router = useRouter() const router = useRouter()
const config = useConfig() const config = useConfig()
const { t } = useI18n() 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() { function clearCache() {
config.$reset() config.$reset()
utils.pop(t('clearCacheSuccess')) 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> </script>
<style scoped></style> <style scoped></style>

View File

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

View File

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

View File

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

View File

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