refactor: rewrite comments in English

This commit is contained in:
Sheng Fan 2025-03-19 12:44:27 +08:00
parent 4a0c3c6231
commit e3202ade12
25 changed files with 370 additions and 354 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

@ -35,7 +35,7 @@ func (a *App) Greet(name string) string {
// ReadAll reads file content
func (a *App) ReadAll(filePath string) string {
// 读取文件内容,得到一个含文件内容和callbackid的json字符串
// Read the file content, resulting in a JSON string containing file content and callback ID
data := string(utils.ReadAll(filePath))
utils.Log("ReadAll data: ", data)
return data

View File

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

View File

@ -1,5 +1,5 @@
<template>
<!-- 全局配置 -->
<!-- Global Configuration -->
<el-config-provider :size="size" :z-index="zIndex" :locale="locale" :button="config" :message="config"
:value-on-clear="null" :empty-values="[undefined, null]">
<RouterView />
@ -10,7 +10,7 @@
import { ref, reactive, onMounted, watch } from 'vue'
import en from 'element-plus/es/locale/lang/en'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
/** 暗黑主题 */
/** Dark Theme */
import { useDark, useStorage } from '@vueuse/core'
const size = 'default'
@ -22,11 +22,11 @@ const localeStr = localConfig.selectedLang ? localConfig.selectedLang.code : 'en
const locale = localeStr == 'en' ? en : zhCn
const isDark = useDark()
//
// Store user preferences
const userPrefersDark = ref(null)
onMounted(() => {
// 使 useStorage isDark
// Use useStorage hook to sync isDark and local storage
useStorage(
'user-prefers-dark',
userPrefersDark,
@ -35,17 +35,17 @@ onMounted(() => {
)
})
// isDark
// Watch isDark changes and update local storage
watch(isDark, (newValue) => {
userPrefersDark.value = newValue ? 'dark' : 'light'
})
/* 全局配置 */
/* Global Configuration */
const config = reactive({
// -
// Button - Automatically insert space between Chinese characters
autoInsertSpace: true,
// -
// Message - Maximum number of messages that can be displayed simultaneously
max: 3,
})
</script>

View File

@ -1,6 +1,6 @@
:root {
--el-menu-base-level-padding: 10px !important;
/** 子菜单缩进 */
/** Indents for submenu items */
--el-menu-level-padding: 20px !important;
}
@ -13,7 +13,7 @@
margin: 0;
padding: 0;
font-family: inherit;
/* 让broder不占用宽度 */
/* Ensure borders don't take up space */
box-sizing: border-box;
}
@ -34,7 +34,7 @@ body {
padding: 0;
line-height: 1.5;
touch-action: none;
/* 不使用原生滚动条 */
/* Don't use native scroll bars */
overflow: hidden;
}
@ -69,7 +69,7 @@ a {
text-decoration: none;
}
/* 防止双击选中 */
/* Avoid double-click selection */
a.no-select {
-webkit-user-select: none;
-moz-user-select: none;
@ -114,12 +114,12 @@ fieldset {
text-align: right;
}
/** 文本缩进默认值,2个字符 */
/** Default indent for text, 2 characters */
.text-indent {
text-indent: 2em;
}
/** \n 换行 */
/** Multiline text preset */
.multiline-text {
white-space: pre-wrap;
word-wrap: break-word;
@ -130,7 +130,7 @@ input:-webkit-autofill,
textarea:-webkit-autofill,
select:-webkit-autofill {
-webkit-text-fill-color: var(--el-text-color);
/* transparent 背景透明 */
/* transparent background */
-webkit-box-shadow: 0 0 0px 1000px transparent inset;
transition: background-color 5000s ease-in-out 0s;
}
@ -151,32 +151,32 @@ input::selection,
input:-webkit-autofill::selection,
input:-webkit-autofill:hover::selection,
input:-webkit-autofill:focus::selection {
/* 设置自动填充时选中文本的样式 */
/* 文字颜色 */
/* Style for autocompleted text */
/* Color for text */
-webkit-text-fill-color: rgb(255, 255, 255);
/* 背景颜色 */
/* Color for background */
background-color: rgb(0, 0, 255);
-webkit-box-shadow: 0 0 0px 1000px rgb(255, 255, 255) inset;
box-shadow: 0 0 0px 1000px rgb(255, 255, 255) inset;
/* 防止背景颜色变化 */
/* Avoid color changes for background */
transition: background-color 5000s ease-in-out 0s;
}
img {
/* 添加渐变效果 */
/* Add transition */
transition: opacity 0.4s ease;
/* 默认透明度为1不透明 */
/* No transparency by default */
opacity: 1;
/* 添加圆角 */
/* Add rounded corners */
border-radius: 6px;
}
img.edit:hover {
/* 鼠标悬停时透明度降为0.5 */
/* Degrade transparency by 0.5 on hover */
opacity: 0.5;
}
/* 渐变边框 */
/* Gradient border */
.gradient-border {
border: 12px solid transparent;
border-radius: 6px;
@ -196,7 +196,7 @@ img.edit:hover {
/** Element Plus Start */
/* 移除全局 el-link 组件的下划线 */
/* Remove underlines globally for el-link */
.el-link::after {
display: none;
}
@ -232,7 +232,7 @@ img.edit:hover {
}
.el-textarea__inner::-webkit-scrollbar {
/* 隐藏滚动条 */
/* Hide scrollbar */
width: 0 !important;
}
@ -253,14 +253,14 @@ button>span.el-button__text--expand {
--el-font-size-base: 11px;
}
/** 菜单样式,菜单组件部分样式必须定义在主类中,
/** Menu styles - Some of the styles are intended to be defined in main classes. */
/* 覆盖el-menu的默认高度 */
/* Override the default height for el-menu */
.el-menu--horizontal {
--el-menu-horizontal-height: 36px;
}
/* 弹出菜单样式 */
/* Styles for pop-up menus */
.el-menu--collapse .el-menu .el-submenu,
.el-menu--popup {
min-width: 120px !important;
@ -268,7 +268,7 @@ button>span.el-button__text--expand {
margin: 0px 0px !important;
}
/* 如果在AsideMenu定义, 关联的菜单组件可能读取不到某些覆盖的样式 */
/* If defined in AsideMenu, menu components associated may not read some overridden styles */
.el-sub-menu__title {
padding: 0px 10px !important;
border-radius: 6px;
@ -280,7 +280,7 @@ button>span.el-button__text--expand {
color: var(--el-color-primary);
}
/** 菜单折叠时hover菜单项高度这里必须再定义一次 */
/* When menu is collapsed, hover menu item height must be redefined */
.el-menu-item {
border-radius: 6px;
height: 32px !important;
@ -301,7 +301,7 @@ button>span.el-button__text--expand {
background-color: rgba(var(--el-color-primary-rgb), .1);
}
/* 分割线样式 */
/* Divider styles */
div.el-divider {
margin: 18px auto;
}
@ -415,7 +415,7 @@ div.el-divider {
align-items: center;
}
/* 全屏居中 */
/* Fullscreen center */
.full-center {
width: 100%;
height: 100%;
@ -563,7 +563,7 @@ div.el-divider {
}
/**
* 可换行的弹性布局
* Flex layout with multiline support
*/
.card-row-wrap {
display: flex;
@ -572,31 +572,31 @@ div.el-divider {
flex-wrap: wrap;
}
/** 卡片行内独占一行, 不能取代card-row-item wp-100 */
/** Exclusive line in a card, doesn't replace card-row-item wp-100 */
.card-row-aline {
width: 100%;
/*防止撑开父元素, 要用flex布局*/
/* Prevent parent element to be affected, need a flex display */
min-width: 0;
margin: 8px 14px;
/** 为子元素预留margin空间 */
/* Reserve margin space for child elements in flex container */
/* padding: 0px 10px; */
display: flex;
justify-content: start;
align-items: center;
}
/** 卡片行普通元素, 有固定宽度,自适应排版 */
/* Card row item with fixed width and adaptive layout */
.card-row-item {
/*防止撑开父元素*/
/* Prevent item from expanding parent container */
min-width: 0;
margin: 8px 14px;
/** 不自动换行,可设置高度 */
/* Flex layout without wrapping */
display: flex;
justify-content: start;
align-items: start;
}
/* 元素水平居中 */
/* Horizontal centering utility class */
.item-h-center {
margin: 0 auto;
}
@ -606,30 +606,30 @@ div.el-divider {
line-height: 32px;
}
/* 第一个子元素 */
/* First child element styling in card rows */
.card-row-item>span:first-child,
.card-row-item>label:first-child {
align-self: start;
width: 100px;
}
/* 第二个子元素是span时 */
/* Second child span element styling */
.card-row-item>span:nth-child(2) {
width: 240px;
padding-left: 12px;
}
/* 第二个子元素是p时 */
/* Second child paragraph element styling */
.card-row-item>p:nth-child(2) {
padding: 5px 12px;
}
/* 第二个子元素 */
/* General second child element styling */
.card-row-item>*:nth-child(2) {
width: 240px;
}
/* 第二个子元素 独占一行时 */
/* Full-width modifier for second child elements */
.card-row-item.wp-100>*:nth-child(2) {
width: calc(100% - 100px);
}
@ -639,7 +639,7 @@ div.el-divider {
}
/**
* card行-无数据
* No data placeholder styling
*/
.card-item-no-data {
width: 100%;
@ -666,17 +666,17 @@ div.el-divider {
margin: -8px -14px;
}
/** 全屏视频背景包装模块 */
/** Full-screen video background container */
.video-bg-wrap {
position: relative;
width: 100%;
height: 100vh;
/** 可设置背景在视频加载前或失败时做显示 设置为深色 */
/* Fallback background for video */
background: #000 url('') no-repeat fixed center center / cover;
overflow: hidden;
}
/** 全屏视频背景包装模块-视频样式 */
/** Video element styling */
.video-bg-wrap video {
z-index: 0;
position: absolute;
@ -687,26 +687,24 @@ div.el-divider {
object-fit: fill;
}
/** 全屏视频背景包装模块-前台内容样式 */
/** Front content overlay for video background */
.video-bg-wrap .front {
z-index: 1;
/* 设置子元素为绝对定位 */
/* Set children to be absolute positioned */
position: absolute;
/* 子元素顶部距离父元素顶部的距离为50% */
/* Center content */
top: 50%;
/* 子元素左侧距离父元素左侧的距离为50% */
left: 50%;
/* 使用transform进行微调将子元素居中 */
transform: translate(-50%, -50%);
/* background-color: rgb(255, 255, 255, 0.9); */
/* 背景模糊 */
/* Blur background */
backdrop-filter: blur(10px);
/* opacity: 0.8; */
border-radius: 6px;
}
/**
* 色彩标签
* Color labels
*/
.color-label {
padding: 2px 6px;
@ -714,7 +712,7 @@ div.el-divider {
}
/**
* 布局管理器遮挡层
* Modal layer for layout manager
*/
.layout-shade {
position: fixed;
@ -751,7 +749,7 @@ div.el-divider {
}
.adv-search {
/** 自动高度过渡动画 */
/** Height transitions for height */
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.3s ease-in-out;
@ -766,7 +764,7 @@ div.el-divider {
}
/**
* 背景颜色
* Background colors
*/
.bg-primary {
background-color: var(--el-color-primary);
@ -789,43 +787,43 @@ div.el-divider {
color: transparent;
}
/* 定义文字渐变色动画 */
/* Color cycling animation for text */
@keyframes text-color-change {
0% {
color: #ff3334;
/* 动画开始时的颜色 */
/* Color for beginning of animation */
}
20% {
color: #ffcf00;
/* 动画中间时的颜色 */
/* Color for middle of animation */
}
40% {
color: #66ccff;
/* 动画中间时的颜色 */
/* Color for middle of animation */
}
60% {
color: #ff3399;
/* 动画中间时的颜色 */
/* Color for middle of animation */
}
80% {
color: #9933ff;
/* 动画中间时的颜色 */
/* Color for middle of animation */
}
100% {
color: #19e713;
/* 动画结束时的颜色 */
/* Color for ending of animation */
}
}
/* 应用动画到元素 */
/* Animated text element */
.animated-text {
animation: text-color-change 2s infinite alternate;
/* 动画名称,持续时间,循环次数,方向 */
/* Animation name, duration, iteration count, direction */
}
@keyframes hue {

View File

@ -1,16 +1,14 @@
import utils from '@/assets/js/utils'
import { ReadAll } from '@/../wailsjs/go/main/App.js'
import utils from '@/assets/js/utils'
// 临时缓存文件信息
// Temporary cache for file information
function cache(fileObj, $event) {
console.log('cache fileObj start:', fileObj, $event.target, $event.dataTransfer)
console.log('Caching 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 new element and append to array
// event.target.files and event.dataTransfer.files are properties related to file upload and drag-drop events
// event.target.files: Used with <input type="file"> elements, contains list of files selected via change event
// event.dataTransfer.files: Contains list of files dropped onto an element via drag-drop event
console.log('$event:', $event, $event.type)
let files
if ($event.type == 'change') {
@ -18,36 +16,36 @@ function cache(fileObj, $event) {
} else if ($event.type == 'drop') {
files = $event.dataTransfer.files
} else {
console.error("无法识别的事件")
console.error("Unrecognized event type")
return
}
const file = files[0]
console.log("file:", file)
console.log("Selected file:", file)
const fileInfo = Array.isArray(fileObj) ? new Object() : fileObj
fileInfo.file = file
let URL = window.URL || window.webkitURL
fileInfo.fileUrl = URL.createObjectURL(file)
const fileType = file.type
console.log(fileType, typeof (fileType))
console.log("File type:", fileType, typeof (fileType))
if (utils.notNull(fileType) && fileType.startsWith("image")) {
fileInfo.imgUrl = fileInfo.fileUrl
}
fileInfo.fileName = file.name
console.log('cache fileObj end:', fileInfo)
console.log('Caching fileObj completed:', fileInfo)
if (Array.isArray(fileObj)) {
// 操作成功后追加到数组末尾
// Append to array after successful operation
fileObj.push(fileInfo)
}
if ($event.type == 'change') {
// 解决选择相同的文件 不触发change事件的问题,放在最后清理
// Clear input to allow reselecting same file
$event.target.value = null
}
}
// 上传文件
// Upload file
async function upload(fileObj) {
console.log("准备开始上传文件!", fileObj, fileObj.file, fileObj.fileId)
// 当前地址
console.log("Preparing to upload file...", fileObj, fileObj.file, fileObj.fileId)
// Current location handling
if (utils.isNull(fileObj.file)) {
if (utils.notNull(fileObj.fileId) && fileObj.remark != fileObj.remarkUpd) {
let remark = null
@ -58,7 +56,7 @@ async function upload(fileObj) {
}
return
}
console.log("开始上传文件!", fileObj, fileObj.file, fileObj.fileId)
console.log("Starting file upload...", fileObj, fileObj.file, fileObj.fileId)
const url = '/common/file/upload'
const formData = new FormData()
formData.append('file', fileObj.file)
@ -73,38 +71,38 @@ async function upload(fileObj) {
}
})
Object.assign(fileObj, data)
console.log("文件同步上传处理完毕", fileObj)
console.log("File upload processed successfully", 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
}
for (let index in fileObjs) {
console.log('fileObjs[index]:', fileObjs, index, fileObjs.length, fileObjs[index])
console.log('Processing file object:', fileObjs, index, fileObjs.length, fileObjs[index])
await upload(fileObjs[index])
console.log("uploads index:", index, "上传文件完毕", fileObjs[index])
console.log("Upload completed for index:", index, fileObjs[index])
}
}
// 上传文件(onChange时)
// Handle file upload (onChange event)
function upOnChg(fileObj, $event) {
const file = $event.target.files[0] || $event.dataTransfer.files[0]
// 当前地址
// Current location
let URL = window.URL || window.webkitURL
// 转成 blob地址
// Convert to blob URL
fileObj.fileUrl = URL.createObjectURL(file)
const url = '/common/file/upload'
const formData = new FormData()
@ -115,12 +113,13 @@ 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
})
}
// Add to component list
function add(fileList) {
const comp = {
index: fileList.length,
@ -134,8 +133,9 @@ function add(fileList) {
fileList.push(comp)
}
// Remove component from list
function del(fileObj, index) {
console.log("fileObj,index:", fileObj, index)
console.log("Deleting file object:", fileObj, index)
if (Array.isArray(fileObj)) {
fileObj.splice(index, 1)
} else {
@ -143,11 +143,12 @@ function del(fileObj, index) {
}
}
// Convert between Java and JS file objects
function trans(javaFile, jsFile) {
if (jsFile == undefined || jsFile == null) {
return
}
// 如果是数组,先清空数组
// Clear array if present
if (jsFile instanceof Array) {
jsFile.splice(0, jsFile.length)
} else {
@ -157,7 +158,7 @@ function trans(javaFile, jsFile) {
if (javaFile == undefined || javaFile == null) {
return
}
// 数组类型
// Handle array type
if (jsFile instanceof Array) {
for (let java of javaFile) {
const js = {}
@ -166,41 +167,40 @@ function trans(javaFile, jsFile) {
jsFile.push(js)
}
} else {
// 对象类型
console.log("对象类型", jsFile instanceof Array)
// Handle object type
console.log("Object type conversion", jsFile instanceof Array)
javaFile.remarkUpd = javaFile.remark
Object.assign(jsFile, javaFile)
}
}
// 从Comps中收集fileId
// Collect file IDs from components
function fileIds(fileList) {
return fileList.map(comp => comp.fileId).join(',')
}
// Read file contents
function readAll(filePath) {
return ReadAll(filePath)
}
export default {
// onChange时缓存
// Cache on change event
cache,
// 上传文件
// Single file upload
upload,
// 上传文件
// Batch file upload
uploads,
// 上传文件
// Immediate upload on change
upOnChg,
// onChange时上传
upOnChg,
// 添加到组件列表
// Add component
add,
// 从组件列表中删除组件
// Remove component
del,
// 文件Java对象与js对象转换
// Object conversion
trans,
// 从Comps中收集fileId
// Collect file IDs
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

@ -1,15 +1,15 @@
import { Greet } from '@/../wailsjs/go/main/App.js'
import axios from "axios"
import { ElMessage } from 'element-plus'
import { Greet } from '@/../wailsjs/go/main/App.js'
/** axios start */
// 创建 axios 实例
// Create a new axios instance
const $axios = axios.create({
baseURL: "api",
timeout: 12000
})
// 请求拦截器
// Request interceptors
$axios.interceptors.request.use(
(config) => {
config.headers["token"] = ''
@ -27,24 +27,24 @@ $axios.interceptors.request.use(
}
)
// 响应拦截器
// Response interceptors
$axios.interceptors.response.use(
(response) => {
// console.log("response:", response)
if (response.status == 200) {
return response.data
} else {
pop("请求错误:" + response.status)
pop("Exception occurred in response:" + 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("Unable to communicate with backend, please retry 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 Go interfaces
*/
function greet(name) {
return Greet(name).then(resp => {
@ -85,78 +85,80 @@ function greet(name) {
}
/**
* 判断对象为空
* Identify whether the object is null
*/
function isNull(obj) {
return obj == undefined || obj == null
}
/**
* 判断对象非空
* Identify whether the object is not null
*/
function notNull(obj) {
return obj != undefined && obj != null
}
/**
* 判断空字符串
* Identify an empty string
*/
function isBlank(str) {
return str == undefined || str == null || /^s*$/.test(str)
}
/**
* 判断不为空字符串
* Identify a non-empty string
*/
function notBlank(str) {
return !isBlank(str)
}
/**
* 判断数组为空
* Identify an empty array
*/
function isEmpty(arr) {
return arr == undefined || arr == null || (arr instanceof Array && arr.length == 0)
}
/**
* 判断数组非空
* Identify a non-empty array
*/
function notEmpty(arr) {
return arr != undefined && arr != null && arr instanceof Array && arr.length > 0
}
/**
* 判断对象为true
* Identify true
*/
function isTrue(obj) {
return obj == true || obj == 'true'
}
/**
* 判断对象为false
* Identify false
*/
function isFalse(obj) {
return !isTrue(obj)
}
/**
* @param {string} str - 要搜索的字符串
* @param {string} char - 要查找的字符
* @returns {number} - 字符在字符串中出现的次数
/**
* Get count of a specific character in a string
* @param {string} str - String to search
* @param {string} char - Character to find
* @returns {number} - Occurrence count
*/
function getCharCount(str, char) {
// 使用g表示整个字符串都要匹配
// g=match globally
var regex = new RegExp(char, 'g')
// match方法可在字符串内检索指定的值或找到一个或多个正则表达式的匹配
// Search for all occurrences of the character in the string
var result = str.match(regex)
var count = !result ? 0 : result.length
return count
}
/**
* 日期格式化
* 默认格式为yyyy-MM-dd HH:mm:ss
* Format date with specified pattern
* @param {Date|string} date - Date object or date string
* @param {string} format - Target format pattern
* @returns {string} - Formatted date string
*/
function dateFormat(date, format) {
if (date == undefined || date == null || date == '') {
@ -187,27 +189,28 @@ function dateFormat(date, format) {
}
/**
* 遍历对象中的日期,并进行格式化
* Recursively format Date properties in objects/arrays
* @param {Object} obj - Target object to process
*/
function fomateDateProperty(obj) {
for (let i in obj) {
//遍历对象中的属性
// Iterate through all properties of the object
if (obj[i] == null) {
continue
} else if (obj[i] instanceof Date) {
// 格式化为yyyy-MM-dd HH:mm:ss
// Format as `yyyy-MM-dd HH:mm:ss`
obj[i] = dateFormat(obj[i])
} else if (obj[i].constructor === Object) {
//如果发现该属性的值还是一个对象,再判空后进行迭代调用
// Recursively format nested objects
if (Object.keys(obj[i]).length > 0) {
//判断对象上是否存在属性,如果为空对象则删除
// Delete empty properties
fomateDateProperty(obj[i])
}
} else if (obj[i].constructor === Array) {
//对象值如果是数组,判断是否为空数组后进入数据遍历判空逻辑
// Recursively clean nested arrays
if (obj[i].length > 0) {
for (let j = 0; j < obj[i].length; j++) {
//遍历数组
// Iterate through all array items
fomateDateProperty(obj[i][j])
}
}
@ -215,35 +218,37 @@ function fomateDateProperty(obj) {
}
}
// 遍历删除对象中的空值属性
/**
* Remove null/empty properties recursively
* @param {Object} obj - Target object to clean
*/
function delNullProperty(obj) {
for (let i in obj) {
//遍历对象中的属性
// Iterate through all properties of the object
if (obj[i] === undefined || obj[i] === null || obj[i] === "") {
//首先除去常规空数据用delete关键字
// Delete general null/empty properties
delete obj[i]
} else if (obj[i].constructor === Object) {
//如果发现该属性的值还是一个对象,再判空后进行迭代调用
// Recursively clean nested objects
if (Object.keys(obj[i]).length === 0) delete obj[i]
//判断对象上是否存在属性,如果为空对象则删除
// Delete empty properties
delNullProperty(obj[i])
} else if (obj[i].constructor === Array) {
//对象值如果是数组,判断是否为空数组后进入数据遍历判空逻辑
// Recursively clean arrays
if (obj[i].length === 0) {
//如果数组为空则删除
// Delete empty arrays
delete obj[i]
} else {
for (let index = 0; index < obj[i].length; index++) {
//遍历数组
// Iterate through all array items
if (obj[i][index] === undefined || obj[i][index] === null || obj[i][index] === "" || JSON.stringify(obj[i][index]) === "{}") {
obj[i].splice(index, 1)
//如果数组值为以上空值则修改数组长度,移除空值下标后续值依次提前
// Delete null/empty array items
index--
//由于数组当前下标内容已经被替换成下一个值,所以计数器需要自减以抵消之后的自增
// Do decrement to avoid skipping next item (index is now pointing to the next item)
}
if (obj[i].constructor === Object) {
//如果发现数组值中有对象,则再次进入迭代
// Recursively clean nested objects in array items
delNullProperty(obj[i])
}
}
@ -253,22 +258,27 @@ function delNullProperty(obj) {
}
/**
* 弹出消息框
* @param msg 消息内容
* @param type
* Display message notification
* @param {string} msg - Message content
* @param {string} type - Message type (success/warning/error/etc)
*/
function pop(msg, type) {
ElMessage({ message: msg, type: type })
}
/**
* Show default message when no data available
* @param {*} data - Data to check
*/
function popNoData(data) {
if (data == undefined || data == null || (data instanceof Array && data.length == 0)) {
ElMessage("暂无数据!")
ElMessage("No data available!")
}
}
/**
* 当前时间字符串
* Get current datetime as formatted string
* @returns {string} Current datetime in yyyy-MM-dd HH:mm format
*/
function nowDatetimeStr() {
const date = new Date()
@ -277,7 +287,9 @@ function nowDatetimeStr() {
}
/**
* 构建分页
* Pagination structure builder
* @param {Object} source - Source pagination data
* @param {Object} target - Target pagination object
*/
function buildPage(source, target) {
target.pageNum = source.pageNum
@ -287,7 +299,8 @@ function buildPage(source, target) {
copyArray(source.list, target.list)
}
/**
* 清空数组
* Clear array contents
* @param {Array} arr - Array to clear
*/
function clearArray(arr) {
if (arr == undefined || arr == null || arr.length == 0) {
@ -295,8 +308,10 @@ function clearArray(arr) {
}
arr.splice(0, arr.length)
}
/**
* 清空属性
* Reset object properties to null
* @param {Object} obj - Target object
*/
function clearProps(obj) {
if (obj == undefined || obj == null) {
@ -308,9 +323,11 @@ function clearProps(obj) {
}
/**
* 复制对象属性
* Copy properties between objects
* @param {Object} source - Source object
* @param {Object} target - Target object
*/
function copyProps(source, target) {
function copyProps(source, target = {}) {
if (target == undefined || target == null) {
target = {}
}
@ -322,13 +339,15 @@ function copyProps(source, target) {
}
}
/**
* 复制数组
* Clone array contents
* @param {Array} source - Source array
* @param {Array} target - Target array
*/
function copyArray(source, target) {
if (target == undefined || target == null) {
return
}
// 先清空数组
// Clear the array first
if (target.length > 0) {
target.splice(0, target.length)
/* while (target.length > 0) {
@ -344,7 +363,10 @@ function copyArray(source, target) {
}
/**
* 发生变更的属性
* Find changed properties between objects
* @param {Object} origin - Original object
* @param {Object} target - Modified object
* @returns {Object} Changed properties
*/
function dfProps(origin, target) {
if (origin == undefined || origin == null || target == undefined || target == null) {
@ -359,9 +381,11 @@ function dfProps(origin, target) {
return dfObj
}
/**
* 是否存在不同属性
* Check for property differences
* @param {Object} origin - Original object
* @param {Object} target - Modified object
* @returns {boolean} True if differences exist
*/
function hasDfProps(origin, target) {
const df = dfProps(origin, target)
@ -374,7 +398,9 @@ function hasDfProps(origin, target) {
}
/**
* 所有字段为空
* Check if all object properties are null
* @param {Object} target - Object to check
* @returns {boolean} True if all properties are null
*/
function isAllPropsNull(target) {
if (target == undefined || target == null) {
@ -437,7 +463,9 @@ function descByLabel(label) {
}
/**
* 重试调用
* Retry calls
* @param {Function} method - Method to call
* @param {any} params - Method parameters that are passed to the method
*/
function retry(method) {
const params = []
@ -450,7 +478,10 @@ function retry(method) {
}
/**
* 根据opts编码匹配中文
* Resolve label from options
* @param {string|number} keyOrVal - Key or value to resolve
* @param {Array} opts - Options array
* @returns {string} Resolved label if found, or original keyOrVal if not found
*/
function resolveLabelFromOpts(keyOrVal, opts) {
if (isEmpty(opts)) {
@ -464,7 +495,11 @@ function resolveLabelFromOpts(keyOrVal, opts) {
return keyOrVal
}
/** 下划线转首字母小写驼峰 */
/**
* Underscored string to camel case string
* @param {String} underscore Underscored string
* @returns Camel case string
*/
function underScoreToCamelCase(underscore) {
if (isNull(underscore) || !underscore.includes('_')) {
return underscore
@ -480,7 +515,12 @@ function underScoreToCamelCase(underscore) {
return words.join("")
}
/** 防抖函数 */
/**
* Debounce a function call
* @param {Function} func Function to debounce
* @param {Number} delay Delay in milliseconds
* @returns Debounced function
*/
function debounce(func, delay) {
let timer
return function () {
@ -500,45 +540,44 @@ function stringToLines(str) {
}
return str.split('\n')
}
export default {
/**
* http请求 GET请求
* Synchronous GET HTTP request
*/
get,
/**
* http请求, 异步等待 GET请求
* Asynchronous GET HTTP request (async/await)
*/
awaitGet,
/**
* http请求 POST请求
* Synchronous POST HTTP request
*/
post,
/**
* http请求, 异步等待 POST请求
* Asynchronous POST HTTP request (async/await)
*/
awaitPost,
/**
* http请求 DELETE请求
* Synchronous DELETE HTTP request
*/
del,
/**
* http请求, 异步等待 DELETE请求
* Asynchronous DELETE HTTP request (async/await)
*/
awaitDel,
/**
* 判断对象为空
* Checks if a value is null/undefined
*/
isNull,
/**
* 判断对象非空
* Verifies a value is not null/undefined
*/
notNull,
@ -547,12 +586,12 @@ export default {
notBlank,
/**
* 判断数组为空
* Checks if an array is empty
*/
isEmpty,
/**
* 判断数组非空
* Verifies an array contains elements
*/
notEmpty,
@ -563,64 +602,62 @@ export default {
getCharCount,
/**
* 弹出消息提示
* Displays a toast notification
*/
pop,
/**
* 判定数据是否为空, 如果为空则提示暂无数据
* Shows "No data" notification for empty datasets
*/
popNoData,
/**
* 遍历删除对象中的空值属性
* Removes null/undefined properties from an object
*/
delNullProperty,
/**
*
* 当前时间字符串
* Gets current datetime as formatted string (YYYY-MM-DD HH:mm:ss)
*/
nowDatetimeStr,
/**
* 构建分页
* Constructs pagination parameters
*/
buildPage,
/**
* 清空数组
* Clears all elements from an array
*/
clearArray,
/**
* 清空属性
* Resets object properties to null/undefined
*/
clearProps,
/**
* 复制对象属性
* Copies properties between objects
*/
copyProps,
/**
* 复制数组
* Creates a shallow array copy
*/
copyArray,
/**
* 日期格式化
* 默认格式为yyyy-MM-dd HH:mm:ss
* Formats Date object to string (customizable format)
*/
dateFormat,
/**
* 遍历对象中的日期,并进行格式化
* Formats Date properties in objects to strings
*/
fomateDateProperty,
/**
* 发生变更的属性
* Tracks changed properties between object states
*/
dfProps,
@ -633,7 +670,7 @@ export default {
descByLabel,
/**
* 重试调用
* Retries failed operations with attempts
*/
retry,

View File

@ -1,15 +1,15 @@
import utils from '@/assets/js/utils'
/** 英文编码正则 */
/** Regex for English letters, numbers, and underscores */
const codeReg = /^[A-Za-z0-9_\-\.]+$/
/** 手机号正则 */
/** Regex for mobile phone number in China (Mainland) */
const mobileReg = /^1[3456789]\d{9}$/
/** 大陆身份证正则 */
/** Regex for ID card number in China (Mainland) */
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正则 */
/** Regex for email */
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 blank'))
} 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('Name too long (max 50 characters)'))
} 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'))
} 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 card number'))
} 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 address'))
} 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('Input must be an integer'))
} else {
callback()
}
@ -92,7 +92,7 @@ function validator() {
console.log("arguments:", arguments)
if (arguments.length <= 1) {
const type = arguments[0]
// 默认校验逻辑, 不含有特殊字符
// Generic validators
if (utils.isBlank(type)) {
return commonValidator
} else if (type == 'notBlank') {
@ -113,22 +113,22 @@ function validator() {
return commonValidator
}
}
// 复合校验器
// Complex validators
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 blank'))
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('In'))
break
}
}
// 兜底callback()只会触发一次
// Ensure callback is called at least once
callback()
}
return complexValidator
@ -138,62 +138,62 @@ export default {
username: (username) => {
if (typeof (username) == "undefined" || username == null) {
return "账号不能为空"
return "Username cannot be blank"
}
username = username.trim()
if (username.length < 4) {
return "账号字符不能小于4位"
return "Username must be at least 4 characters long"
}
if (username.length > 20) {
return "账号字符不能大于20位"
return "Username must be at most 20 characters long"
}
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 blank"
}
password = password.trim()
if (password.length < 4) {
return "密码字符不能小于4位"
return "Password must be at least 4 characters long"
}
if (password.length > 20) {
return "密码字符不能大于20位"
return "Password must be at most 20 characters long"
}
const reg = /^[A-Za-z0-9\.\-\_\+]+$/
if (!reg.test(password)) {
return "密码为必须为字母和数字或.-+_"
return "Password must be letters, numbers, and special characters (.-_+) only"
}
return null
},
email: (email) => {
if (typeof (email) == "undefined" || email == null) {
return "邮箱不能为空"
return "Email cannot be blank"
}
const reg = /^[A-Za-z0-9._%-]+@([A-Za-z0-9-]+\.)+[A-Za-z]{2,4}$/
if (!reg.test(email)) {
return "邮箱格式不正确"
return "Invalid email address"
}
return null
},
validCode: (validCode) => {
if (typeof (validCode) == "undefined" || validCode == null) {
return "验证码不能为空"
return "Verification code cannot be blank"
}
validCode = validCode.trim()
if (validCode.length != 6) {
return "验证码必须为6位"
return "Verification code must be 6 characters long"
}
const reg = /^[A-Za-z0-9]{6}$/
if (!reg.test(validCode)) {
return "验证码格式不正确"
return "Invalid verification code format"
}
return null
},

View File

@ -1,12 +1,12 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { terser } from 'rollup-plugin-terser'
import AutoImport from 'unplugin-auto-import/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
// https://vitejs.dev/config/
export default defineConfig({
@ -37,16 +37,16 @@ export default defineConfig({
},
build: {
chunkSizeWarningLimit: 1500,
// 分解块,将大块分解成更小的块
// Split into chunks
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
// 让每个插件都打包成独立的文件
return id.toString().split('node_modules/')[1].split('/')[0].toString();
// Pack each package into a separate chunk
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
},
// 单位b, 合并较小模块
// In bytes, merge small modules
experimentalMinChunkSize: 10 * 1024,
}
},

View File

@ -52,7 +52,7 @@ const handleClose = (key, keyPath) => {
// console.log(key, keyPath)
}
//
// Menu List
const menuList = [
{
index: "M02",
@ -89,7 +89,7 @@ const menuList = [
]
onMounted(() => {
// ,
// Check menu position after refresh
// activeMenu()
})
@ -107,11 +107,11 @@ function listSubMenu(menuCode) {
watch(() => router.currentRoute.value.path, (newValue, oldValue) => {
// console.log('LeftMenurouter.currentRoute.value.path', newValue, oldValue)
// ,
// Check menu position after route change
activeMenu()
})
//
// Check activated menu position
function activeMenu() {
const currRoute = router.currentRoute
const path = currRoute.value.path
@ -121,13 +121,13 @@ function activeMenu() {
if (utils.notNull(index)) {
return index
}
// ,path,
// No match, try to find menu for parent path
const lastIndex = path.lastIndexOf('/')
if (lastIndex != -1) {
const newPath = path.substring(0, lastIndex)
console.log("截取后newPath:", newPath)
console.log("newPath from parent path:", newPath)
index = getIndexByPath(newPath)
console.log("截取后index:", index)
console.log("index from parent path:", index)
if (utils.notNull(index)) {
return index
}
@ -135,7 +135,7 @@ function activeMenu() {
return "1"
}
// index
// Query menu index by path
function getIndexByPath(path) {
for (let fstMenu of menuList) {
// console.log(fstMenu.index, fstMenu.href == path)
@ -157,7 +157,7 @@ function getIndexByPath(path) {
return thdMenu.index
}
}
// path,to
// If no third-level menu path matches, use the 'to' from the route configuration to find a match
for (let thdMenu of thdMenuList) {
const nodeList = routeMap.get(path)
if (utils.isEmpty(nodeList)) {
@ -165,14 +165,14 @@ function getIndexByPath(path) {
}
for (let node of nodeList) {
if (node.to == thdMenu.href) {
// console.log("node.to:", node.to)
// console.log("A match was found for node.to:", node.to)
return thdMenu.index
}
}
}
}
}
// ,to
// Iterate through each secondary menu item in the secMenuList
for (let secMenu of secMenuList) {
// console.log(secMenu.index, secMenu.href == path)
const nodeList = routeMap.get(path)
@ -187,13 +187,13 @@ function getIndexByPath(path) {
}
}
}
// ,to
// None of the menu items match the path, try to find a match for the 'to' from the route configuration
}
}
// routes
const routes = router.options.routes;
// get routes configuration
const routes = router.options.routes
// console.log("routes:", routes)
const routeMap = new Map()
routes.forEach(lv1 => {
@ -261,7 +261,7 @@ function getMenuNameByCode(code) {
<style scoped>
span {
/* 防止双击选中 */
/* Prevent text selection from double-clicking */
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
@ -269,16 +269,16 @@ span {
}
span {
/* 字体大小 */
/* Font size */
font-size: 16px;
}
li {
/* 字体大小 */
/* Font size */
font-size: 15px;
}
/** 菜单折叠时hover菜单项高度这里必须再定义一次 */
/** When the menu is collapsed, redefine the hover menu height */
.el-menu-item {
min-width: 44px;
height: 36px;

View File

@ -25,17 +25,18 @@
</el-header>
<el-main>
<el-scrollbar style="width: 100%;">
<!-- 路由展示区 -->
<!-- { Component }指当前路由所对应的组件 -->
<!-- Router View Container -->
<!-- { Component } = currently matched route component -->
<RouterView v-slot="{ Component }">
<!-- 添加过渡动画 需要确保插入的component元素只有一个根节点, 否则报错. component中的根元素的transition会覆盖transitionName的样式
而且需要保证component中根元素的宽度相同所以最好是统一给component添加一个根元素 -->
<!-- Cached Route Transition: Only keeps alive components with keepAlive meta flag
Transition animation requires single root element in component Key ensures proper re-rendering on route path changes -->
<transition :name="transitionName">
<KeepAlive>
<Component :is="Component" v-if="keepAlive" :key="$route.path" />
</KeepAlive>
</transition>
<!-- 添加过渡动画 需要确保插入的component元素只有一个根节点 -->
<!-- Non-cached Route Transition: Fresh instance for other components
Separate transition to prevent animation conflicts -->
<transition :name="transitionName">
<Component :is="Component" v-if="!keepAlive" :key="$route.path" />
</transition>
@ -66,46 +67,49 @@ const config = useConfig()
const { shrink, menuCollapse } = storeToRefs(config)
const currentRoute = reactive(router.currentRoute)
// ,
// Default transition effect, slide to the left
let transitionName = 'slide-left'
const keepAlive = computed(() => {
return currentRoute.value.meta.keepAlive
})
/** 固定菜单头展开折叠动画时间 刷新页面时菜单不会展开或折叠, 设置持续时间为0, 不产生动画 */
/**
* Set the menu animation duration to 0ms on page refresh to prevent the menu from expanding or collapsing
* with an animation. This ensures that the menu state remains consistent after a page reload.
*/
const menuAnimationDuration = ref(0)
//
// Function to toggle the menu between expanded and collapsed states
function menuToggle() {
menuAnimationDuration.value = '300ms'
if (menuCollapse.value) {
// console.log(", ")
// console.log("Extend menu")
if (shrink.value) {
// ,
// Expend the shade if menu is collapsing
showShade(() => {
// console.log(", , ")
// Callback function to close the shade after the menu has collapsed
config.setMenuCollapse(true)
})
}
} else {
// console.log(", , ")
// If the menu is in an expanded state, close the shade
closeShade()
}
//
// Toggle the menu state
config.setMenuCollapse(!menuCollapse.value)
}
function onAdaptiveLayout() {
//
// Get the current window width
const clientWidth = document.body.clientWidth
// console.log("menuCollapse:", menuCollapse.value, config.getMenuCollapse(), "clientWidth:", clientWidth)
// aside
// Determine if the aside menu should be shrunk based on the window width
if (clientWidth < 800) {
config.setShrink(true)
if (!menuCollapse.value) {
// ,
// Collapse the menu if it is not already collapsed
menuToggle()
}
} else {
@ -119,16 +123,15 @@ onBeforeMount(() => {
})
watch(() => router.currentRoute.value.path, (newValue, oldValue) => {
// console.log(",,:", newValue, oldValue)
// If the layout is shrunk and the menu is expanded, collapse the menu
if (shrink.value && !menuCollapse.value) {
// console.log(", , ")
menuToggle()
}
})
function refresh() {
// console.log("")
// Reload the page
location.reload()
}
@ -182,7 +185,7 @@ main {
white-space: nowrap;
}
/** 菜单折叠 */
/* Keyframes for the menu collapse animation */
@keyframes menuCollapse {
0% {
width: 200px;
@ -193,7 +196,7 @@ main {
}
}
/** 菜单展开 */
/* Keyframes for the menu expand animation */
@keyframes menuExpand {
0% {
width: 44px;
@ -209,9 +212,9 @@ main {
z-index: 9999;
height: 44px;
width: 44px;
/* 引用上面定义的@keyframes名称 */
/* Reference to the keyframes */
animation-name: menuCollapse;
/* 动画持续时间 */
/* Duration of the animation */
animation-duration: v-bind('menuAnimationDuration');
animation-timing-function: ease-in-out;
background-color: var(--el-fg-color);
@ -222,13 +225,13 @@ main {
z-index: 9999;
height: 44px;
width: 200px;
/* 引用上面定义的@keyframes名称 */
/* Reference to the keyframes */
animation-name: menuExpand;
/* 动画持续时间 */
/* Duration of the animation */
animation-duration: v-bind('menuAnimationDuration');
animation-timing-function: ease-in-out;
background-color: var(--el-fg-color);
z-index: 9999999
z-index: 9999999;
}
.scrollbar-menu-wrapper {
@ -240,6 +243,6 @@ main {
.scrollbar-menu-wrapper.shrink {
position: fixed;
left: 0;
z-index: 9999999
z-index: 9999999;
}
</style>

View File

@ -1,25 +1,25 @@
import './assets/css/main.css'
import files from '@/assets/js/files'
import utils from '@/assets/js/utils'
import verify from '@/assets/js/verify'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import files from '@/assets/js/files'
import verify from '@/assets/js/verify'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import i18n from './locales/i18n'
import router from './router'
// import ElementPlus from 'element-plus'
import { ElMessage } from 'element-plus'
import 'element-plus/dist/index.css'
/* 暗黑主题模式 */
import 'element-plus/theme-chalk/dark/css-vars.css'
import '@/assets/less/light.css'
/* Dark theme configuration */
import '@/assets/less/dark.css'
// 定义特性标志
window.__VUE_PROD_DEVTOOLS__ = false;
window.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = false;
import '@/assets/less/light.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
// Configure Vue production flags
window.__VUE_PROD_DEVTOOLS__ = false
window.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = false
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
@ -28,21 +28,21 @@ const app = createApp(App)
app.use(pinia)
// 全局引用router
// Globally reference router
app.use(router)
app.use(i18n)
// ElMessage需要在utils中使用,这里单独引入
// Register Element Plus Message component globally (required for use in utils)
app.use(ElMessage)
// 全局使用
// Global configuration of ElementPlus
// ElSelect.props.placeholder.default = '请选择'
// 在引入 ElementPlus 时,可以传入一个包含 size 和 zIndex 属性的全局配置对象。
// size 用于设置表单组件的默认尺寸zIndex 用于设置弹出组件的层级zIndex 的默认值为 2000。
// When ElementPlus is imported, a global configuration object can be passed in which contains size and zIndex properties
// size is used to set the default size of form components, and zIndex is used to set the layer level of pop-up components.
// app.use(ElementPlus, { locale, size: 'default', zIndex: 2000 })
// 使用vue3 provide注册
// Configure global providers for shared utilities
app.provide('utils', utils)
@ -52,4 +52,3 @@ app.provide('verify', verify)
/* app.provide('uuid', uuidv4) */
app.mount('#app')

View File

@ -1,12 +1,12 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { terser } from 'rollup-plugin-terser'
import AutoImport from 'unplugin-auto-import/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
// https://vitejs.dev/config/
export default defineConfig({
@ -37,16 +37,16 @@ export default defineConfig({
},
build: {
chunkSizeWarningLimit: 1500,
// 分解块,将大块分解成更小的块
// Fine-tune bundling strategy
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
// 让每个插件都打包成独立的文件
return id.toString().split('node_modules/')[1].split('/')[0].toString();
// Extract package name from module path to create separate chunks
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
},
// 单位b, 合并较小模块
// Attempt to merge chunks smaller than 10KB (in bytes)
experimentalMinChunkSize: 10 * 1024,
}
},

View File

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

View File

@ -1,8 +0,0 @@
def factorial(n):
if n == 0 or n == 1:
return 1
else:
return n * factorial(n - 1)
# Example usage
print(factorial(5))

View File

@ -1,2 +0,0 @@
Hello, World!
This is a sample text file.