This commit is contained in:
2025-12-06 14:49:46 +08:00
parent 68c91b4ba3
commit 39579ff75f
63 changed files with 20089 additions and 53 deletions

View File

@@ -3,7 +3,7 @@
# Log file # Log file
*.log *.log
*/logs
# BlueJ files # BlueJ files
*.ctxt *.ctxt

View File

@@ -1,4 +1,4 @@
package org.xyzh.api.crontab; package org.xyzh.api.crontab.service;
/** /**
* 定时任务服务接口 * 定时任务服务接口

View File

@@ -25,8 +25,8 @@ public class SysUserVO extends BaseVO {
@Schema(description = "用户ID") @Schema(description = "用户ID")
private String userId; private String userId;
@Schema(description = "用户") @Schema(description = "用户编码")
private String username; private String usercode;
@Schema(description = "密码(敏感信息,仅用于创建/修改)") @Schema(description = "密码(敏感信息,仅用于创建/修改)")
private String password; private String password;
@@ -47,21 +47,15 @@ public class SysUserVO extends BaseVO {
private String userType; private String userType;
// TbSysUserInfoDTO对应字段 // TbSysUserInfoDTO对应字段
@Schema(description = "用户名")
private String username;
@Schema(description = "头像") @Schema(description = "头像")
private String avatar; private String avatar;
@Schema(description = "性别") @Schema(description = "性别")
private Integer gender; private Integer gender;
@Schema(description = "")
private String familyName;
@Schema(description = "")
private String givenName;
@Schema(description = "全名")
private String fullName;
@Schema(description = "等级") @Schema(description = "等级")
private Integer level; private Integer level;
@@ -87,7 +81,7 @@ public class SysUserVO extends BaseVO {
} }
TbSysUserDTO dto = new TbSysUserDTO(); TbSysUserDTO dto = new TbSysUserDTO();
dto.setUserId(vo.getUserId()); dto.setUserId(vo.getUserId());
dto.setUsername(vo.getUsername()); dto.setUsercode(vo.getUsercode());
dto.setPassword(vo.getPassword()); dto.setPassword(vo.getPassword());
dto.setEmail(vo.getEmail()); dto.setEmail(vo.getEmail());
dto.setPhone(vo.getPhone()); dto.setPhone(vo.getPhone());

View File

@@ -20,8 +20,8 @@ public class TbSysUserDTO extends BaseDTO {
@Schema(description = "用户ID") @Schema(description = "用户ID")
private String userId; private String userId;
@Schema(description = "用户") @Schema(description = "用户编码")
private String username; private String usercode;
@Schema(description = "密码") @Schema(description = "密码")
private String password; private String password;

View File

@@ -26,14 +26,8 @@ public class TbSysUserInfoDTO extends BaseDTO {
@Schema(description = "性别") @Schema(description = "性别")
private Integer gender; private Integer gender;
@Schema(description = "") @Schema(description = "用户名称")
private String familyName; private String username;
@Schema(description = "")
private String givenName;
@Schema(description = "全名")
private String fullName;
@Schema(description = "等级") @Schema(description = "等级")
private Integer level; private Integer level;

56
urbanLifelineWeb/.gitignore vendored Normal file
View File

@@ -0,0 +1,56 @@
.vscode/chrome-debug-profile
packages/*/node_modules
node_modules
docs
# Dependencies
node_modules/
.pnpm-store/
.pnpm-debug.log
# Build outputs
dist/
**/dist/
**/build/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Environment files
.env
.env.*
!.env.example
# Local development
.cache/
.temp/
.turbo/
# Testing
coverage/
**/coverage/
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Misc
.DS_Store
Thumbs.db

5
urbanLifelineWeb/.npmrc Normal file
View File

@@ -0,0 +1,5 @@
auto-install-peers=true
shamefully-hoist=true
shared-workspace-lockfile=false
strict-peer-dependencies=false
prefer-frozen-lockfile=true

View File

@@ -1,21 +1,6 @@
{ {
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{
"name": "Launch Chrome (Shared)",
"type": "chrome",
"request": "launch",
"url": "http://localhost:5000",
"webRoot": "${workspaceFolder}/packages/shared",
"runtimeExecutable": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"sourceMaps": true,
"sourceMapPathOverrides": {
"/@/*": "${workspaceFolder}/packages/shared/*",
"/src/*": "${workspaceFolder}/packages/shared/src/*"
},
"userDataDir": "${workspaceFolder}/.vscode/chrome-debug-profile",
"trace": true
},
{ {
"name": "启动 Shared 开发服务器", "name": "启动 Shared 开发服务器",
"type": "node-terminal", "type": "node-terminal",
@@ -30,14 +15,45 @@
"showReuseMessage": true, "showReuseMessage": true,
"clear": false "clear": false
} }
},
{
"name": "启动 Platform 开发服务器",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev",
"cwd": "${workspaceFolder}/packages/platform",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"showReuseMessage": true,
"clear": false
}
},
{
"name": "启动 Bidding 开发服务器",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev",
"cwd": "${workspaceFolder}/packages/bidding",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"showReuseMessage": true,
"clear": false
}
} }
], ],
"compounds": [ "compounds": [
{ {
"name": "启动 Shared 并打开 Chrome", "name": "启动所有 Web 项目",
"configurations": [ "configurations": [
"启动 Shared 开发服务器", "启动 Shared 开发服务器",
"Launch Chrome (Shared)" "启动 Platform 开发服务器",
"启动 Bidding 开发服务器"
], ],
"stopAll": true, "stopAll": true,
"presentation": { "presentation": {

107
urbanLifelineWeb/README.md Normal file
View File

@@ -0,0 +1,107 @@
# Urban Lifeline Web 微前端项目
基于 Import Maps 的微前端架构,包含共享模块和多个业务应用。
## 📦 项目结构
```
urbanLifelineWeb/
├── packages/
│ ├── shared/ # 共享模块 (端口 5000)
│ ├── platform/ # 主平台应用 (端口 5001)
│ ├── bidding/ # 招标管理应用 (端口 5002)
│ └── workcase/ # 案例管理应用 (端口 5003)
└── package.json
```
## 🚀 快速开始
### 1. 安装依赖
```bash
# 一键安装所有包的依赖
npm run install:all
# 或单独安装
npm run install:shared
npm run install:platform
npm run install:bidding
npm run install:workcase
```
### 2. 启动开发服务器
```bash
# 同时启动所有服务
npm run dev:all
# 或单独启动
npm run dev:shared # http://localhost:5000
npm run dev:platform # http://localhost:5001
npm run dev:bidding # http://localhost:5002
npm run dev:workcase # http://localhost:5003
```
### 3. 构建生产版本
```bash
# 构建所有应用
npm run build:all
# 或单独构建
npm run build:shared
npm run build:platform
npm run build:bidding
npm run build:workcase
```
## 🌐 端口分配
| 服务 | 端口 | 说明 |
|------|------|------|
| Shared | 5000 | 共享组件和工具库 |
| Platform | 5001 | 主平台应用 |
| Bidding | 5002 | 招标管理应用 |
| Workcase | 5003 | 案例管理应用 |
## 🔧 技术栈
- **框架**: Vue 3.5 + TypeScript
- **构建工具**: Vite 6.0
- **UI 组件库**: Element Plus 2.9
- **状态管理**: Pinia 2.2
- **路由**: Vue Router 4.5
- **工具库**: VueUse
## 📝 开发说明
### Import Maps
本项目使用 Import Maps 实现模块共享:
```html
<script type="importmap">
{
"imports": {
"@shared/components": "http://localhost:5000/shared/components.js",
"@shared/utils": "http://localhost:5000/shared/utils.js",
"@shared/api": "http://localhost:5000/shared/api.js"
}
}
</script>
```
### API 代理
所有应用的 `/api` 请求会代理到后端服务 `http://localhost:8080`
### 跨域配置
开发环境下所有服务已启用 CORS支持跨域访问。
## 🔥 注意事项
1. **启动顺序**: 建议先启动 `shared` 服务,再启动其他应用
2. **端口占用**: 确保 5000-5003 端口未被占用
3. **Node 版本**: 建议使用 Node.js 18+
4. **依赖安装**: 首次运行前必须执行 `npm run install:all`

View File

@@ -0,0 +1,72 @@
@echo off
echo ====================================
echo Urban Lifeline Web - 安装依赖脚本
echo ====================================
echo.
echo [1/5] 安装根项目依赖...
call npm install
if errorlevel 1 (
echo 根项目依赖安装失败!
pause
exit /b 1
)
echo.
echo [2/5] 安装 shared 模块依赖...
cd packages\shared
call npm install
if errorlevel 1 (
echo Shared 模块依赖安装失败!
pause
exit /b 1
)
cd ..\..
echo.
echo [3/5] 安装 platform 应用依赖...
cd packages\platform
call npm install
if errorlevel 1 (
echo Platform 应用依赖安装失败!
pause
exit /b 1
)
cd ..\..
echo.
echo [4/5] 安装 bidding 应用依赖...
cd packages\bidding
call npm install
if errorlevel 1 (
echo Bidding 应用依赖安装失败!
pause
exit /b 1
)
cd ..\..
echo.
echo [5/5] 安装 workcase 应用依赖...
cd packages\workcase
call npm install
if errorlevel 1 (
echo Workcase 应用依赖安装失败!
pause
exit /b 1
)
cd ..\..
echo.
echo ====================================
echo ✓ 所有依赖安装完成!
echo ====================================
echo.
echo 下一步:
echo 启动所有服务: npm run dev:all
echo 或单独启动:
echo - Shared: npm run dev:shared
echo - Platform: npm run dev:platform
echo - Bidding: npm run dev:bidding
echo - Workcase: npm run dev:workcase
echo.
pause

5170
urbanLifelineWeb/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
{
"name": "urbanlifeline-web",
"version": "1.0.0",
"private": true,
"type": "module",
"packageManager": "pnpm@8.10.0",
"scripts": {
"dev": "pnpm -r --parallel --filter \"@*/*\" run dev",
"build": "pnpm -r --filter \"@*/*\" run build",
"clean": "rimraf node_modules && rimraf packages/*/node_modules"
},
"devDependencies": {
"concurrently": "^9.1.0",
"rimraf": "^5.0.5"
},
"engines": {
"node": ">=16.0.0",
"pnpm": ">=8.0.0"
},
"workspaces": [
"packages/*"
]
}

View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="/favicon.ico">
<title>招标管理系统</title>
<!-- 加载运行时配置(必须在其他脚本之前加载) -->
<script src="/app-config.js"></script>
<!-- Import Maps 配置 - 引用共享模块 -->
<script type="importmap">
{
"imports": {
"@shared/components": "http://localhost:5000/shared/components.js",
"@shared/utils": "http://localhost:5000/shared/utils.js",
"@shared/api": "http://localhost:5000/shared/api.js",
"@shared/composables": "http://localhost:5000/shared/composables.js",
"@shared/types": "http://localhost:5000/shared/types.js"
}
}
</script>
<!-- 预加载关键模块 -->
<link rel="modulepreload" href="http://localhost:5000/shared/components.js">
<link rel="modulepreload" href="http://localhost:5000/shared/utils.js">
</head>
<body>
<div id="app"></div>
<!-- ES Module 入口 -->
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -0,0 +1,27 @@
{
"name": "@urbanlifeline/bidding",
"version": "1.0.0",
"type": "module",
"private": true,
"scripts": {
"dev": "vite --port 5002 --host",
"build": "vue-tsc && vite build",
"preview": "vite preview --port 5002"
},
"dependencies": {
"vue": "^3.5.13",
"vue-router": "^4.5.0",
"pinia": "^2.2.8",
"element-plus": "^2.9.1",
"@vueuse/core": "^11.3.0",
"axios": "^1.7.9"
},
"devDependencies": {
"@types/node": "^22.0.0",
"@vitejs/plugin-vue": "^5.2.1",
"@vitejs/plugin-vue-jsx": "^4.1.1",
"typescript": "^5.7.2",
"vite": "^6.0.3",
"vue-tsc": "^2.2.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/**
* @description 应用运行时配置文件
* @author yslg
* @since 2025-12-06
*
* 说明:
* 1. 此文件在生产环境中被加载,用于覆盖内置配置
* 2. Docker 部署时,可通过挂载此文件来修改配置,无需重新构建
* 3. 配置结构必须与 packages/shared/src/config/index.ts 中的 AppRuntimeConfig 保持一致
*
* 使用示例Docker
* docker run -v /path/to/app-config.js:/app/public/app-config.js my-app:latest
*/
window.APP_RUNTIME_CONFIG = {
// 环境标识
env: 'production',
// API 配置
api: {
baseUrl: '/api',
timeout: 30000
},
// 应用基础路径
baseUrl: '/',
// 文件配置
file: {
downloadUrl: '/api/file/download/',
uploadUrl: '/api/file/upload',
maxSize: {
image: 5, // MB
video: 100, // MB
document: 10 // MB
},
acceptTypes: {
image: 'image/*',
video: 'video/*',
document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx'
}
},
// Token 配置
token: {
key: 'token',
refreshThreshold: 300000 // 5分钟
},
// 公共资源路径
publicImgPath: '/img',
publicWebPath: '/',
// 功能开关
features: {
enableDebug: false,
enableMockData: false
}
};

View File

@@ -0,0 +1,32 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["node"],
"jsx": "preserve",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"isolatedModules": true,
"noEmit": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@shared/*": ["../shared/src/*"]
}
},
"include": [
"src/**/*",
"*.ts",
"*.vue"
],
"exclude": [
"node_modules",
"dist"
]
}

View File

@@ -0,0 +1,49 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
export default defineConfig({
plugins: [vue(), vueJsx()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
server: {
port: 5002,
host: true,
cors: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/api/, '')
},
// 代理共享模块请求到 shared 服务
'/shared': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
},
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'element-plus': ['element-plus']
}
}
}
}
})

View File

@@ -6,6 +6,9 @@
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<title>泰豪电源 AI 数智化平台</title> <title>泰豪电源 AI 数智化平台</title>
<!-- 加载运行时配置(必须在其他脚本之前加载) -->
<script src="/app-config.js"></script>
<!-- Import Maps 配置 - 只配置共享模块 --> <!-- Import Maps 配置 - 只配置共享模块 -->
<script type="importmap"> <script type="importmap">
{ {

View File

@@ -0,0 +1,27 @@
{
"name": "@urbanlifeline/platform",
"version": "1.0.0",
"type": "module",
"private": true,
"scripts": {
"dev": "vite --port 5001 --host",
"build": "vue-tsc && vite build",
"preview": "vite preview --port 5001"
},
"dependencies": {
"vue": "^3.5.13",
"vue-router": "^4.5.0",
"pinia": "^2.2.8",
"element-plus": "^2.9.1",
"@vueuse/core": "^11.3.0",
"axios": "^1.7.9"
},
"devDependencies": {
"@types/node": "^22.0.0",
"@vitejs/plugin-vue": "^5.2.1",
"@vitejs/plugin-vue-jsx": "^4.1.1",
"typescript": "^5.7.2",
"vite": "^6.0.3",
"vue-tsc": "^2.2.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/**
* @description 应用运行时配置文件
* @author yslg
* @since 2025-12-06
*
* 说明:
* 1. 此文件在生产环境中被加载,用于覆盖内置配置
* 2. Docker 部署时,可通过挂载此文件来修改配置,无需重新构建
* 3. 配置结构必须与 packages/shared/src/config/index.ts 中的 AppRuntimeConfig 保持一致
*
* 使用示例Docker
* docker run -v /path/to/app-config.js:/app/public/app-config.js my-app:latest
*/
window.APP_RUNTIME_CONFIG = {
// 环境标识
env: 'production',
// API 配置
api: {
baseUrl: '/api',
timeout: 30000
},
// 应用基础路径
baseUrl: '/',
// 文件配置
file: {
downloadUrl: '/api/file/download/',
uploadUrl: '/api/file/upload',
maxSize: {
image: 5, // MB
video: 100, // MB
document: 10 // MB
},
acceptTypes: {
image: 'image/*',
video: 'video/*',
document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx'
}
},
// Token 配置
token: {
key: 'token',
refreshThreshold: 300000 // 5分钟
},
// 公共资源路径
publicImgPath: '/img',
publicWebPath: '/',
// 功能开关
features: {
enableDebug: false,
enableMockData: false
}
};

View File

@@ -0,0 +1,32 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["node"],
"jsx": "preserve",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"isolatedModules": true,
"noEmit": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@shared/*": ["../shared/src/*"]
}
},
"include": [
"src/**/*",
"*.ts",
"*.vue"
],
"exclude": [
"node_modules",
"dist"
]
}

View File

@@ -0,0 +1,49 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
export default defineConfig({
plugins: [vue(), vueJsx()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
server: {
port: 5001,
host: true,
cors: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/api/, '')
},
// 代理共享模块请求到 shared 服务
'/shared': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
},
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'element-plus': ['element-plus']
}
}
}
}
})

File diff suppressed because it is too large Load Diff

View File

@@ -4,25 +4,27 @@
"type": "module", "type": "module",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite --port 5000 --host", "dev": "vite",
"build": "run-p build:*", "build": "run-p build:*",
"build:esm": "vite build --mode esm", "build:esm": "vite build --mode esm",
"build:federation": "vite build --mode federation", "build:federation": "vite build --mode federation",
"preview": "vite preview --port 5000" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-router": "^4.5.0", "ofetch": "^1.4.1"
"pinia": "^2.2.8",
"element-plus": "^2.9.1",
"@vueuse/core": "^11.3.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.10.0",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
"@vitejs/plugin-vue-jsx": "^4.1.1", "@vitejs/plugin-vue-jsx": "^4.1.1",
"typescript": "^5.7.2",
"vite": "^6.0.3",
"@originjs/vite-plugin-federation": "^1.3.6", "@originjs/vite-plugin-federation": "^1.3.6",
"npm-run-all": "^4.1.5" "npm-run-all": "^4.1.5",
"typescript": "^5.7.2",
"vite": "^6.0.3"
},
"peerDependencies": {
"vue": "^3.5.13",
"typescript": ">=5.0.0"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,298 @@
import axios, { AxiosResponse, AxiosError, InternalAxiosRequestConfig } from "axios";
import { ElLoading, ElMessage } from "element-plus";
import type { ResultDomain } from "@/types";
import { API_BASE_URL } from "@/config";
/**
* 扩展AxiosRequestConfig以支持自定义配置
*/
interface CustomAxiosRequestConfig extends Partial<InternalAxiosRequestConfig> {
/** 是否显示加载动画 */
showLoading?: boolean;
/** 是否显示错误提示 */
showError?: boolean;
/** 是否需要token */
requiresAuth?: boolean;
}
/**
* Token管理
*/
export const TokenManager = {
/** 获取token从localStorage获取并检查过期 */
getToken(): string | null {
const itemStr = localStorage.getItem('token');
if (!itemStr) return null;
try {
const item = JSON.parse(itemStr);
const now = Date.now();
// 检查是否过期
if (item.timestamp && item.expiresIn) {
if (now - item.timestamp > item.expiresIn) {
// 已过期,删除
localStorage.removeItem('token');
return null;
}
}
return item.value || itemStr; // 兼容旧数据
} catch {
// 如果不是JSON格式直接返回兼容旧数据
return itemStr;
}
},
/** 设置token始终使用localStorage根据rememberMe设置过期时间 */
setToken(token: string, rememberMe = false): void {
const data = {
value: token,
timestamp: Date.now(),
// 如果不勾选"记住我"设置1天过期时间勾选则7天
expiresIn: rememberMe ? 7 * 24 * 60 * 60 * 1000 : 1 * 24 * 60 * 60 * 1000
};
localStorage.setItem('token', JSON.stringify(data));
},
/** 移除token */
removeToken(): void {
localStorage.removeItem('token');
},
/** 检查是否有token */
hasToken(): boolean {
return !!this.getToken();
}
};
/**
* 创建axios实例
*
* 说明:
* - 统一使用配置模块提供的 API_BASE_URL 作为基础路径
* - API_BASE_URL 在开发环境来自 devConfig在生产环境来自 window.APP_RUNTIME_CONFIG
*/
const request = axios.create({
baseURL: API_BASE_URL,
timeout: 30000,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
}
});
let loadingInstance: ReturnType<typeof ElLoading.service> | null = null;
/**
* 请求拦截器
*/
request.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
const customConfig = config as CustomAxiosRequestConfig;
// 默认不显示加载动画,只有 showLoading 为 true 时才展示
if (customConfig.showLoading === true) {
loadingInstance = ElLoading.service({
lock: true,
text: "加载中...",
background: "rgba(0, 0, 0, 0.7)",
});
}
// 添加token
const token = TokenManager.getToken();
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
// 自动处理 FormData删除 Content-Type让浏览器自动设置包含 boundary
if (config.data instanceof FormData && config.headers) {
delete config.headers['Content-Type'];
}
return config;
},
(error: AxiosError) => {
if (loadingInstance) {
loadingInstance.close();
loadingInstance = null;
}
return Promise.reject(error);
}
);
/**
* 响应拦截器
*/
request.interceptors.response.use(
(response: AxiosResponse<ResultDomain<any>>) => {
// 关闭加载动画
if (loadingInstance) {
loadingInstance.close();
loadingInstance = null;
}
const result = response.data;
// 检查是否为ResultDomain格式
if (result && typeof result === 'object' && 'code' in result) {
// 检查登录状态
if (result.login === false) {
ElMessage.error(result.message || '请先登录');
TokenManager.removeToken();
// 跳转到登录页
window.location.href = '/login';
return Promise.reject(new Error('未登录'));
}
// 检查权限
if (result.auth === false) {
ElMessage.error(result.message || '没有权限访问');
return Promise.reject(new Error('无权限'));
}
// // 检查业务逻辑是否成功 业务逻辑不应该提前判断
// if (!result.success) {
// const config = response.config as CustomAxiosRequestConfig;
// if (config.showError !== false) {
// ElMessage.error(result.message || '操作失败');
// }
// return Promise.reject(new Error(result.message || '操作失败'));
// }
// 返回成功的数据
return response;
}
// 非ResultDomain格式直接返回
return response;
},
(error: AxiosError<ResultDomain<any>>) => {
// 关闭加载动画
if (loadingInstance) {
loadingInstance.close();
loadingInstance = null;
}
const config = error.config as CustomAxiosRequestConfig;
// 处理HTTP错误
if (error.response) {
const { status, data } = error.response;
switch (status) {
case 401:
ElMessage.error('认证失败,请重新登录');
TokenManager.removeToken();
window.location.href = '/login';
break;
case 403:
ElMessage.error('没有权限访问该资源');
break;
case 404:
ElMessage.error('请求的资源不存在');
break;
case 500:
ElMessage.error(data?.message || '服务器内部错误');
break;
default:
if (config?.showError !== false) {
ElMessage.error(data?.message || '请求失败');
}
}
} else if (error.request) {
// 请求已发送但没有收到响应
ElMessage.error('网络错误,请检查网络连接');
} else {
// 其他错误
if (config?.showError !== false) {
ElMessage.error(error.message || '请求失败');
}
}
return Promise.reject(error);
}
);
/**
* API封装
*/
export const api = {
/**
* GET请求 - data参数会作为URL查询参数追加
*/
get<T = any>(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise<AxiosResponse<ResultDomain<T>>> {
// 如果有data参数将其转换为URL查询参数
if (data) {
const params = new URLSearchParams();
Object.keys(data).forEach(key => {
if (data[key] !== undefined && data[key] !== null) {
params.append(key, String(data[key]));
}
});
const queryString = params.toString();
url += (url.includes('?') ? '&' : '?') + queryString;
}
return request.get<ResultDomain<T>>(url, config);
},
/**
* POST请求 - data参数放到请求体
*/
post<T = any>(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise<AxiosResponse<ResultDomain<T>>> {
return request.post<ResultDomain<T>>(url, data, config);
},
/**
* PUT请求 - data参数放到请求体
*/
put<T = any>(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise<AxiosResponse<ResultDomain<T>>> {
return request.put<ResultDomain<T>>(url, data, config);
},
/**
* DELETE请求 - data参数放到请求体
*/
delete<T = any>(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise<AxiosResponse<ResultDomain<T>>> {
return request.delete<ResultDomain<T>>(url, { ...config, data });
},
/**
* PATCH请求 - data参数放到请求体
*/
patch<T = any>(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise<AxiosResponse<ResultDomain<T>>> {
return request.patch<ResultDomain<T>>(url, data, config);
},
/**
* 文件上传
*/
upload<T = any>(url: string, formData: FormData, config?: CustomAxiosRequestConfig): Promise<AxiosResponse<ResultDomain<T>>> {
return request.post<ResultDomain<T>>(url, formData, {
...config,
headers: {
'Content-Type': 'multipart/form-data',
...(config?.headers as Record<string, string>)
}
});
},
/**
* 文件下载
*/
download(url: string, filename?: string, config?: CustomAxiosRequestConfig): Promise<void> {
return request.get(url, {
...config,
responseType: 'blob'
}).then((response) => {
const blob = new Blob([response.data]);
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = filename || 'download';
link.click();
window.URL.revokeObjectURL(link.href);
});
}
};
export default request;

View File

@@ -0,0 +1,226 @@
/**
* @description 应用运行时配置
* @author yslg
* @since 2025-12-06
*
* 配置加载策略:
* 1. 开发环境:使用下面定义的开发配置
* 2. 生产环境:从 window.APP_RUNTIME_CONFIG 读取(来自 app-config.js
* 3. Docker部署替换 app-config.js 文件实现配置外挂
*
* 配置结构说明:
* 此文件的配置结构与 app-config.js 完全对应
* 修改 app-config.js 后,这里的配置会自动应用
*/
// ============================================
// 类型定义
// ============================================
export interface AppRuntimeConfig {
env?: string;
api: {
baseUrl: string;
timeout: number;
};
baseUrl: string;
file: {
downloadUrl: string;
uploadUrl: string;
maxSize: {
image: number;
video: number;
document: number;
};
acceptTypes: {
image: string;
video: string;
document: string;
};
};
token: {
key: string;
refreshThreshold: number;
};
publicImgPath: string;
publicWebPath: string;
features?: {
enableDebug?: boolean;
enableMockData?: boolean;
[key: string]: any;
};
}
// ============================================
// 配置定义(与 app-config.js 结构一致)
// ============================================
const isDev = (import.meta as any).env?.DEV ?? false;
// 开发环境配置
const devConfig: AppRuntimeConfig = {
env: 'development',
api: {
// 开发环境通过 Vite 代理转发到后端,避免浏览器直接跨域
// 实际请求路径示例:/api/... → 由代理转发到实际后端
baseUrl: '/api',
timeout: 30000
},
baseUrl: '/',
file: {
// 同样走代理,保持与 api.baseUrl 一致
downloadUrl: '/api/file/download/',
uploadUrl: '/api/file/upload',
maxSize: {
image: 5,
video: 100,
document: 10
},
acceptTypes: {
image: 'image/*',
video: 'video/*',
document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx'
}
},
token: {
key: 'token',
refreshThreshold: 300000
},
publicImgPath: 'http://localhost:5173/img',
publicWebPath: 'http://localhost:5173',
features: {
enableDebug: true,
enableMockData: false
}
};
// 生产环境默认配置(兜底)
const prodDefaultConfig: AppRuntimeConfig = {
env: 'production',
api: {
baseUrl: '/api',
timeout: 30000
},
baseUrl: '/',
file: {
downloadUrl: '/api/file/download/',
uploadUrl: '/api/file/upload',
maxSize: {
image: 5,
video: 100,
document: 10
},
acceptTypes: {
image: 'image/*',
video: 'video/*',
document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx'
}
},
token: {
key: 'token',
refreshThreshold: 300000
},
publicImgPath: '/img',
publicWebPath: '/',
features: {
enableDebug: false,
enableMockData: false
}
};
// ============================================
// 配置加载
// ============================================
/**
* 获取运行时配置
* 生产环境优先从 window.APP_RUNTIME_CONFIG 读取app-config.js 注入)
*/
const getRuntimeConfig = (): AppRuntimeConfig => {
if (isDev) {
console.log('[配置] 开发环境,使用内置配置');
return devConfig;
}
// 生产环境:尝试读取外部配置
try {
const runtimeConfig = (window as any).APP_RUNTIME_CONFIG;
if (runtimeConfig && typeof runtimeConfig === 'object') {
console.log('[配置] 加载外部配置 app-config.js');
console.log('[配置] API地址:', runtimeConfig.api?.baseUrl);
console.log('[配置] 环境:', runtimeConfig.env || 'production');
return runtimeConfig as AppRuntimeConfig;
}
} catch (e) {
console.warn('[配置] 无法读取外部配置,使用默认配置', e);
}
console.log('[配置] 使用默认生产配置');
return prodDefaultConfig;
};
// 当前应用配置
const config = getRuntimeConfig();
console.log('[配置] 当前配置', config);
// ============================================
// 导出配置(向后兼容)
// ============================================
// 单独导出常用配置项
export const API_BASE_URL = config.api.baseUrl;
export const FILE_DOWNLOAD_URL = config.file.downloadUrl;
export const PUBLIC_IMG_PATH = config.publicImgPath;
export const PUBLIC_WEB_PATH = config.publicWebPath;
// 导出完整配置对象
export const APP_CONFIG = {
// 应用标题
title: '泰豪电源 AI 数智化平台',
// 环境标识
env: config.env || 'production',
// 应用基础路径
baseUrl: config.baseUrl,
// API 配置
api: {
baseUrl: config.api.baseUrl,
timeout: config.api.timeout
},
// 文件配置
file: {
downloadUrl: config.file.downloadUrl,
uploadUrl: config.file.uploadUrl,
maxSize: config.file.maxSize,
acceptTypes: config.file.acceptTypes
},
// Token 配置
token: {
key: config.token.key,
refreshThreshold: config.token.refreshThreshold
},
// 公共路径
publicImgPath: config.publicImgPath,
publicWebPath: config.publicWebPath,
// 功能开关
features: config.features || {}
};
// 默认导出
export default APP_CONFIG;

View File

@@ -0,0 +1,139 @@
/**
* Agent服务相关 types - 根据后端 VO 和 DTO 转换
*/
import { BaseVO, BaseDTO } from "@/types/base"
// KnowledgeBaseVO - 知识库
export interface KnowledgeBaseVO extends BaseVO {
/** 知识库ID */
knowledgeId?: string
/** 智能体ID */
agentId?: string
/** 智能体名称 */
agentName?: string
/** 知识库名称 */
name?: string
/** 知识库类型 */
kbType?: string
/** 知识库类型名称 */
kbTypeName?: string
/** 访问级别 */
accessLevel?: string
/** 访问级别名称 */
accessLevelName?: string
/** 知识库描述 */
description?: string
/** 存储路径 */
storagePath?: string
/** 当前版本号 */
version?: string
/** 知识库配置 */
config?: Record<string, any>
/** 服务类型 */
serviceType?: string
/** 部门名称 */
deptName?: string
}
// KnowledgeDocumentVO - 知识文档
export interface KnowledgeDocumentVO extends BaseVO {
/** 文档ID */
documentId?: string
/** 知识库ID */
knowledgeId?: string
/** 文档名称 */
name?: string
/** 文档类型 */
docType?: string
/** 文档内容 */
content?: string
/** 文档描述 */
description?: string
/** 文档状态 */
status?: string
/** 文件路径 */
filePath?: string
/** 文件大小 */
fileSize?: number
}
// KnowledgeChunkVO - 知识块(分块存储)
export interface KnowledgeChunkVO extends BaseVO {
/** 块ID */
chunkId?: string
/** 文档ID */
documentId?: string
/** 知识库ID */
knowledgeId?: string
/** 块内容 */
content?: string
/** 块索引 */
chunkIndex?: number
/** 向量嵌入 */
embedding?: number[]
/** 相似度 */
similarity?: number
}
// KnowledgeBaseDTO - 知识库DTO创建和更新
export interface KnowledgeBaseDTO extends BaseDTO {
/** 知识库ID */
knowledgeId?: string
/** 智能体ID */
agentId?: string
/** 知识库名称 */
name?: string
/** 知识库类型 */
kbType?: string
/** 访问级别 */
accessLevel?: string
/** 知识库描述 */
description?: string
/** 存储路径 */
storagePath?: string
/** 当前版本号 */
version?: string
/** 知识库配置 */
config?: Record<string, any>
/** 服务类型 */
serviceType?: string
}
// KnowledgeDocumentDTO - 知识文档DTO创建和更新
export interface KnowledgeDocumentDTO extends BaseDTO {
/** 文档ID */
documentId?: string
/** 知识库ID */
knowledgeId?: string
/** 文档名称 */
name?: string
/** 文档类型 */
docType?: string
/** 文档内容 */
content?: string
/** 文档描述 */
description?: string
/** 文档状态 */
status?: string
/** 文件路径 */
filePath?: string
/** 文件大小 */
fileSize?: number
}
// KnowledgeChunkDTO - 知识块DTO创建和更新
export interface KnowledgeChunkDTO extends BaseDTO {
/** 块ID */
chunkId?: string
/** 文档ID */
documentId?: string
/** 知识库ID */
knowledgeId?: string
/** 块内容 */
content?: string
/** 块索引 */
chunkIndex?: number
/** 向量嵌入 */
embedding?: number[]
}

View File

@@ -0,0 +1 @@
export * from "./agent"

View File

@@ -0,0 +1,41 @@
/**
* 认证服务相关 types - 根据后端 VO 和 DTO 转换
*/
// LoginParam - 登录参数
export interface LoginParam {
/** 登录用户名或邮箱或手机 */
username?: string
/** 登录密码 */
password?: string
/** 验证码 */
captcha?: string
/** 验证码ID */
captchaId?: string
/** 登录方式password/captcha/oauth */
loginType?: string
}
// LoginDomain - 登录信息
export interface LoginDomain {
/** 用户ID */
userId?: string
/** 用户名 */
username?: string
/** 邮箱 */
email?: string
/** 手机 */
phone?: string
/** 访问令牌 */
accessToken?: string
/** 刷新令牌 */
refreshToken?: string
/** 令牌类型 */
tokenType?: string
/** 过期时间(秒) */
expiresIn?: number
/** 用户权限列表 */
permissions?: string[]
/** 用户角色列表 */
roles?: string[]
}

View File

@@ -0,0 +1 @@
export * from "./auth"

View File

@@ -0,0 +1,38 @@
/**
* 基础DTO - 包含所有数据传输对象的公共字段
*/
export interface BaseDTO {
/** 操作流水号 */
optsn?: string
/** 创建人 */
creator?: string
/** 更新人 */
updater?: string
/** 部门路径 */
deptPath?: string
/** 备注 */
remark?: string
/** 创建时间 */
createTime?: string
/** 更新时间 */
updateTime?: string
/** 删除时间 */
deleteTime?: string
/** 是否已删除 */
deleted?: boolean
}
/**
* 基础VO - 包含所有实体的公共字段
*/
export interface BaseVO extends BaseDTO {
/** 主键ID */
id?: string
orderTypes?: OrderType[]
}
export interface OrderType {
field: string
order: 'ASC' | 'DESC'
}

View File

@@ -0,0 +1,117 @@
/**
* 竞价服务相关 types - 根据后端 VO 和 DTO 转换
*/
import { BaseVO, BaseDTO } from "@/types/base"
// BiddingProjectVO - 招标项目详情
export interface BiddingProjectVO extends BaseVO {
/** 项目ID */
projectId?: string
/** 项目编号 */
projectNo?: string
/** 项目名称 */
projectName?: string
/** 项目类型 */
projectType?: string
/** 项目类型名称(中文) */
projectTypeName?: string
/** 所属行业 */
industry?: string
/** 来源平台 */
sourcePlatform?: string
/** 来源URL */
sourceUrl?: string
/** 发布日期 */
publishDate?: string
/** 投标截止日期 */
deadline?: string
/** 开标日期 */
openingDate?: string
/** 距离截止日期剩余天数 */
daysUntilDeadline?: number
/** 预算金额 */
budgetAmount?: number
/** 货币单位 */
currency?: string
/** 预算金额格式化显示 */
budgetAmountFormatted?: string
/** 项目状态 */
projectStatus?: string
/** 项目状态名称(中文) */
projectStatusName?: string
/** 中标状态 */
winningStatus?: string
/** 中标状态名称(中文) */
winningStatusName?: string
/** 中标金额 */
winningAmount?: number
/** 中标金额格式化显示 */
winningAmountFormatted?: string
/** 客户名称 */
clientName?: string
/** 客户联系方式 */
clientContact?: string
/** 联系人 */
contactPerson?: string
/** 项目地点 */
projectLocation?: string
/** 项目描述 */
description?: string
/** 关键词 */
keywords?: string[]
/** 负责人 */
responsibleUser?: string
/** 团队成员 */
teamMembers?: string[]
}
// BiddingProjectDTO - 招标项目DTO创建和更新
export interface BiddingProjectDTO extends BaseDTO {
/** 项目ID更新时需要 */
projectId?: string
/** 项目编号 */
projectNo?: string
/** 项目名称 */
projectName?: string
/** 项目类型 */
projectType?: string
/** 所属行业 */
industry?: string
/** 来源平台 */
sourcePlatform?: string
/** 来源URL */
sourceUrl?: string
/** 发布日期 */
publishDate?: string
/** 投标截止日期 */
deadline?: string
/** 开标日期 */
openingDate?: string
/** 预算金额 */
budgetAmount?: number
/** 货币单位 */
currency?: string
/** 项目状态 */
projectStatus?: string
/** 中标状态 */
winningStatus?: string
/** 中标金额 */
winningAmount?: number
/** 客户名称 */
clientName?: string
/** 客户联系方式 */
clientContact?: string
/** 联系人 */
contactPerson?: string
/** 项目地点 */
projectLocation?: string
/** 项目描述 */
description?: string
/** 关键词 */
keywords?: string[]
/** 负责人 */
responsibleUser?: string
/** 团队成员 */
teamMembers?: string[]
}

View File

@@ -0,0 +1 @@
export * from "./bidding"

View File

@@ -0,0 +1,121 @@
/**
* 定时任务服务相关 types - 根据后端 VO 和 DTO 转换
*/
import { BaseVO, BaseDTO } from "@/types/base"
// CrontabTaskVO - 定时任务详情
export interface CrontabTaskVO extends BaseVO {
/** 任务ID */
taskId?: string
/** 任务名称 */
taskName?: string
/** 任务分组 */
taskGroup?: string
/** 任务元数据ID */
metaId?: string
/** 元数据名称 */
metaName?: string
/** 是否使用默认接收人 */
defaultRecipient?: boolean
/** Bean名称 */
beanName?: string
/** 方法名称 */
methodName?: string
/** 方法参数 */
methodParams?: string
/** Cron表达式 */
cronExpression?: string
/** Cron表达式描述中文 */
cronDescription?: string
/** 任务状态 */
status?: number
/** 任务状态名称 */
statusName?: string
/** 任务描述 */
description?: string
/** 是否允许并发执行 */
concurrent?: boolean
/** 错过执行策略 */
misfirePolicy?: number
/** 错过执行策略名称 */
misfirePolicyName?: string
/** 下次执行时间 */
nextExecuteTime?: string
/** 最后执行时间 */
lastExecuteTime?: string
/** 最后执行状态0-失败/1-成功 */
lastExecuteStatus?: number
}
// TbCrontabTaskDTO - 定时任务DTO创建和更新
export interface TbCrontabTaskDTO extends BaseDTO {
/** 任务ID更新时需要 */
taskId?: string
/** 任务名称 */
taskName?: string
/** 任务分组 */
taskGroup?: string
/** 任务元数据ID */
metaId?: string
/** 是否使用默认接收人 */
defaultRecipient?: boolean
/** Bean名称 */
beanName?: string
/** 方法名称 */
methodName?: string
/** 方法参数 */
methodParams?: string
/** Cron表达式 */
cronExpression?: string
/** 任务状态 */
status?: number
/** 任务描述 */
description?: string
/** 是否允许并发执行 */
concurrent?: boolean
/** 错过执行策略 */
misfirePolicy?: number
}
// CrontabLogVO - 定时任务执行日志
export interface CrontabLogVO extends BaseVO {
/** 日志ID */
logId?: string
/** 任务ID */
taskId?: string
/** 任务名称 */
taskName?: string
/** 执行状态 */
status?: number
/** 执行状态名称 */
statusName?: string
/** 执行开始时间 */
startTime?: string
/** 执行结束时间 */
endTime?: string
/** 执行耗时(毫秒) */
duration?: number
/** 执行结果 */
result?: string
/** 错误信息 */
errorMessage?: string
}
// TbCrontabLogDTO - 定时任务日志DTO
export interface TbCrontabLogDTO extends BaseDTO {
/** 日志ID */
logId?: string
/** 任务ID */
taskId?: string
/** 执行状态 */
status?: number
/** 执行开始时间 */
startTime?: string
/** 执行结束时间 */
endTime?: string
/** 执行结果 */
result?: string
/** 错误信息 */
errorMessage?: string
}

View File

@@ -0,0 +1 @@
export * from "./crontab"

View File

@@ -0,0 +1,27 @@
/**
* 文件服务相关 types - 根据后端 VO 和 DTO 转换
*/
import { BaseDTO } from "@/types/base"
// TbSysFileDTO - 系统文件DTO
export interface TbSysFileDTO extends BaseDTO {
/** 文件ID (主键) */
fileId?: string
/** 文件名 */
name?: string
/** 文件路径 */
path?: string
/** 文件大小(字节) */
size?: number
/** 文件类型 */
type?: string
/** 存储类型 */
storageType?: string
/** MIME 类型 */
mimeType?: string
/** 文件访问 URL */
url?: string
/** 文件状态 */
status?: string
}

View File

@@ -0,0 +1 @@
export * from "./file"

View File

@@ -0,0 +1,13 @@
export * from "./response"
export * from "./page"
export * from "./base"
export * from "./sys"
// 服务 types
export * from "./auth"
export * from "./file"
export * from "./message"
export * from "./agent"
export * from "./crontab"
export * from "./bidding"
export * from "./workcase"

View File

@@ -0,0 +1 @@
export * from "./message"

View File

@@ -0,0 +1,71 @@
/**
* 消息服务相关 types - 根据后端 VO 和 DTO 转换
*/
import { BaseVO, BaseDTO } from "@/types/base"
// MessageVO - 消息(包含消息详情和发送范围)
export interface MessageVO extends BaseVO {
/** 消息ID */
messageId?: string
/** 消息标题 */
title?: string
/** 消息内容 */
content?: string
/** 消息类型 */
type?: string
/** 消息状态 */
status?: string
/** 消息发送范围列表 */
messageRanges?: MessageRangeChannelVO[]
/** 消息接收记录列表(管理员查看时使用) */
messageReceivers?: TbMessageReceiverDTO[]
}
// MessageRangeChannelVO - 消息发送范围
export interface MessageRangeChannelVO extends BaseVO {
/** 发送范围ID */
rangeId?: string
/** 消息ID */
messageId?: string
/** 渠道类型 */
channelType?: string
/** 渠道名称 */
channelName?: string
/** 接收人范围 */
recipientRange?: string
/** 接收人范围名称 */
recipientRangeName?: string
}
// TbMessageReceiverDTO - 消息接收记录
export interface TbMessageReceiverDTO extends BaseDTO {
/** 接收记录ID */
receiverId?: string
/** 消息ID */
messageId?: string
/** 接收人ID */
userId?: string
/** 接收人名称 */
userName?: string
/** 接收状态 */
status?: string
/** 接收时间 */
receiveTime?: string
/** 读取时间 */
readTime?: string
}
// TbMessageDTO - 消息DTO创建和更新
export interface TbMessageDTO extends BaseDTO {
/** 消息ID */
messageId?: string
/** 消息标题 */
title?: string
/** 消息内容 */
content?: string
/** 消息类型 */
type?: string
/** 消息状态 */
status?: string
}

View File

@@ -0,0 +1,28 @@
/**
* 分页参数
*/
export interface PageParam {
/** 当前页码 */
pageNumber: number;
/** 每页条数 */
pageSize: number;
/** 总页数 */
totalPages?: number;
/** 总记录数 */
totalElements?: number;
}
/**
* 分页结果
*/
export interface PageDomain<T> {
pageParam: PageParam;
/** 数据列表 */
dataList?: T[];
}
export interface PageRequest<T> {
pageParam: PageParam;
filter: T;
}

View File

@@ -0,0 +1,21 @@
import type { PageParam, PageDomain } from "@/types/page";
export interface ResultDomain<T>{
/** 状态码 */
code: number;
/** 返回消息 */
message: string;
/** 操作是否成功 */
success: boolean;
/** 是否登录 */
login: boolean;
/** 是否有权限 */
auth: boolean;
/** 返回数据 */
data?: T;
/** 返回数据列表 */
dataList?: T[];
/** 分页参数 */
pageParam?: PageParam;
/** 分页信息 */
pageDomain?: PageDomain<T>;
}

View File

@@ -0,0 +1,60 @@
import { BaseVO, BaseDTO } from "@/types/base";
export interface SysConfigVO extends BaseVO {
/** 配置ID */
configId?: string;
/** 配置键 */
key?: string;
/** 配置名称 */
name?: string;
/** 配置值 */
value?: string;
/** 数据类型(String, Integer, Boolean, Float, Double) */
configType?: string;
/** 配置渲染类型(select, input, textarea, checkbox, radio, switch) */
renderType?: string;
/** 配置描述 */
description?: string;
/** 正则表达式校验规则(JSON) */
re?: Record<string, any>;
/** 可选项(JSON)render_type为select、checkbox、radio时使用 */
options?: Record<string, any>;
/** 配置组 */
group?: string;
/** 模块ID */
moduleId?: string;
/** 配置顺序 */
orderNum?: number;
/** 状态 */
status?: number;
}
// TbSysConfigDTO - 系统配置DTO创建和更新
export interface TbSysConfigDTO extends BaseDTO {
/** 配置ID */
configId?: string;
/** 配置键 */
key?: string;
/** 配置名称 */
name?: string;
/** 配置值 */
value?: string;
/** 数据类型(String, Integer, Boolean, Float, Double) */
configType?: string;
/** 配置渲染类型(select, input, textarea, checkbox, radio, switch) */
renderType?: string;
/** 配置描述 */
description?: string;
/** 正则表达式校验规则(JSON) */
re?: Record<string, any>;
/** 可选项(JSON)render_type为select、checkbox、radio时使用 */
options?: Record<string, any>;
/** 配置组 */
group?: string;
/** 模块ID */
moduleId?: string;
/** 配置顺序 */
orderNum?: number;
/** 配置状态 0:启用 1:禁用 */
status?: number;
}

View File

@@ -0,0 +1,3 @@
export * from "./config"
export * from "./permission"
export * from "./user"

View File

@@ -0,0 +1,239 @@
import { BaseVO, BaseDTO } from "@/types/base";
export interface PermissionVO extends BaseVO {
/** 部门ID */
deptId?: string;
/** 部门名称 */
deptName?: string;
/** 父级部门ID */
deptParentId?: string;
/** 部门描述 */
deptDescription?: string;
/** 角色ID */
roleId?: string;
/** 角色名称 */
roleName?: string;
/** 角色描述 */
roleDescription?: string;
/** 角色作用域 */
roleScope?: string;
/** 所属部门ID */
roleOwnerDeptId?: string;
/** 角色状态 */
roleStatus?: boolean;
/** 模块ID */
moduleId?: string;
/** 模块名称 */
moduleName?: string;
/** 模块描述 */
moduleDescription?: string;
/** 权限ID */
permissionId?: string;
/** 权限名称 */
permissionName?: string;
/** 权限代码 */
permissionCode?: string;
/** 权限描述 */
permissionDescription?: string;
/** 权限状态 */
permissionStatus?: string;
/** 视图ID */
viewId?: string;
/** 视图名称 */
viewName?: string;
/** 父视图ID */
viewParentId?: string;
/** URL */
viewUrl?: string;
/** 组件 */
viewComponent?: string;
/** 图标 */
viewIcon?: string;
/** 类型 */
viewType?: number;
/** 布局 */
viewLayout?: string;
/** 排序 */
viewOrderNum?: number;
/** 视图描述 */
viewDescription?: string;
/** 用户视图权限列表 */
permissionIdList?: string[];
}
// TbSysDeptDTO - 系统部门DTO
export interface TbSysDeptDTO extends BaseDTO {
/** 部门ID */
deptId?: string;
/** 部门名称 */
name?: string;
/** 父级部门ID */
parentId?: string;
/** 部门描述 */
description?: string;
}
// TbSysDeptRoleDTO - 系统部门角色关系DTO
export interface TbSysDeptRoleDTO extends BaseDTO {
/** 部门ID */
deptId?: string;
/** 角色ID */
roleId?: string;
}
// TbSysRoleDTO - 系统角色DTO
export interface TbSysRoleDTO extends BaseDTO {
/** 角色ID */
roleId?: string;
/** 角色名称 */
name?: string;
/** 角色描述 */
description?: string;
/** 角色作用域 global 全局角色, dept 部门角色 */
scope?: string;
/** 所属部门ID */
ownerDeptId?: string;
/** 角色状态 true 有效, false 无效 */
status?: boolean;
}
// TbSysModuleDTO - 系统模块DTO
export interface TbSysModuleDTO extends BaseDTO {
/** 模块ID */
moduleId?: string;
/** 模块名称 */
name?: string;
/** 模块描述 */
description?: string;
}
// TbSysViewDTO - 系统视图DTO
export interface TbSysViewDTO extends BaseDTO {
/** 视图ID */
viewId?: string;
/** 视图名称 */
name?: string;
/** 父视图ID */
parentId?: string;
/** URL */
url?: string;
/** 组件 */
component?: string;
/** 图标 */
icon?: string;
/** 类型 */
type?: number;
/** 布局 */
layout?: string;
/** 排序 */
orderNum?: number;
/** 描述 */
description?: string;
}
// TbSysPermissionDTO - 系统权限DTO
export interface TbSysPermissionDTO extends BaseDTO {
/** 权限ID */
permissionId?: string;
/** 权限名称 */
name?: string;
/** 权限代码 */
code?: string;
/** 权限描述 */
description?: string;
/** 模块ID */
moduleId?: string;
/** 状态 */
status?: string;
}
// TbSysRolePermissionDTO - 系统角色权限关系DTO
export interface TbSysRolePermissionDTO extends BaseDTO {
/** 角色ID */
roleId?: string;
/** 权限ID */
permissionId?: string;
}
// TbSysViewPermissionDTO - 系统视图权限关系DTO
export interface TbSysViewPermissionDTO extends BaseDTO {
/** 视图ID */
viewId?: string;
/** 权限ID */
permissionId?: string;
}
// =============== 数据权限 ===============
export interface AclVO extends BaseVO {
/** 权限ID */
aclId?: string;
/** 对象类型article/file/course/... */
objectType?: string;
/** 对象ID */
objectId?: string;
/** 主体类型user/dept/role */
principalType?: string;
/** 主体ID */
principalId?: string;
/** 当主体为role且限定到某部门时的部门ID支持某部门的某角色 */
principalDeptId?: string;
/** 权限位1读 2写 4执行 */
permission?: number;
/** 允许或显式拒绝 */
allow?: boolean;
/** 是否包含子级对dept/role生效 */
includeDescendants?: boolean;
/** 策略ID */
policyId?: string;
/** 策略名称 */
policyName?: string;
/** 对象类型article/file/course/.. */
policyObjectType?: string;
/** 编辑层级规则parent_only/parent_or_same_admin/owner_only/none */
editHierarchyRule?: string;
/** 可见层级规则 children_all/children_specified/none */
viewHierarchyRule?: string;
}
// TbSysAclDTO - 系统访问控制列表DTO创建和更新
export interface TbSysAclDTO extends BaseDTO {
/** 权限ID */
aclId?: string;
/** 对象类型article/file/course/... */
objectType?: string;
/** 对象ID */
objectId?: string;
/** 主体类型user/dept/role */
principalType?: string;
/** 主体ID */
principalId?: string;
/** 当主体为role且限定到某部门时的部门ID支持某部门的某角色 */
principalDeptId?: string;
/** 权限位1读 2写 4执行 */
permission?: number;
/** 允许或显式拒绝 */
allow?: boolean;
/** 是否包含子级对dept/role生效 */
includeDescendants?: boolean;
}
// TbSysAclPolicyDTO - 系统访问控制策略DTO
export interface TbSysAclPolicyDTO extends BaseDTO {
/** 策略ID */
policyId?: string;
/** 策略名称 */
name?: string;
/** 对象类型article/file/course/.. */
objectType?: string;
/** 编辑层级规则parent_only/parent_or_same_admin/owner_only/none */
editHierarchyRule?: string;
/** 可见层级规则 children_all/children_specified/none */
viewHierarchyRule?: string;
/** 默认权限无显式ACL时应用 */
defaultPermission?: number;
/** 默认是否允许 */
defaultAllow?: boolean;
/** 是否默认应用到子级 */
applyToChildren?: boolean;
}

View File

@@ -0,0 +1,138 @@
import { BaseVO, BaseDTO } from "@/types/base";
import { PermissionVO } from "@/types/sys/permission";
export interface SysUserVO extends BaseVO {
/** 用户ID */
userId?: string;
/** 用户编码 */
usercode?: string;
/** 密码(敏感信息,仅用于创建/修改) */
password?: string;
/** 邮箱 */
email?: string;
/** 手机 */
phone?: string;
/** 微信ID */
wechatId?: string;
/** 用户状态 */
status?: string;
/** 用户类型 */
userType?: string;
/** 用户名 */
username?: string;
/** 头像 */
avatar?: string;
/** 性别 */
gender?: number;
/** 等级 */
level?: number;
/** 身份证号 */
idCard?: string;
/** 地址 */
address?: string;
/** 用户部门角色列表 */
deptRoles?: UserDeptRoleVO[];
/** 用户角色权限列表 */
rolePermissions?: PermissionVO[];
/** 用户视图权限列表 */
viewPermissions?: PermissionVO[];
}
export interface UserDeptRoleVO extends BaseVO {
/** 用户ID */
userId?: string;
/** 密码 */
password?: string;
/** 邮箱 */
email?: string;
/** 手机 */
phone?: string;
/** 微信ID */
wechatId?: string;
/** 用户状态 */
status?: string;
/** 用户类型 */
userType?: string;
/** 头像 */
avatar?: string;
/** 用户名 */
username?: string;
/** 性别 */
gender?: number;
/** 等级 */
level?: number;
/** 身份证号 */
idCard?: string;
/** 地址 */
address?: string;
/** 部门ID */
deptId?: string;
/** 部门名称 */
deptName?: string;
/** 父级部门ID */
parentId?: string;
/** 部门描述 */
deptDescription?: string;
/** 角色ID */
roleId?: string;
/** 角色名称 */
roleName?: string;
/** 角色描述 */
roleDescription?: string;
/** 角色作用域 */
scope?: string;
/** 所属部门ID */
ownerDeptId?: string;
/** 角色状态 */
roleStatus?: boolean;
}
// DTO 类型
// TbSysUserDTO - 系统用户DTO创建和更新
export interface TbSysUserDTO extends BaseDTO {
/** 用户ID */
userId?: string;
/** 用户编码 */
usercode?: string;
/** 密码 */
password?: string;
/** 邮箱 */
email?: string;
/** 手机(加密) */
phone?: string;
/** 手机号哈希 */
phone_hash?: string;
/** 微信ID */
wechatId?: string;
/** 用户状态 */
status?: string;
/** 用户类型 */
userType?: string;
}
// TbSysUserInfoDTO - 系统用户信息DTO
export interface TbSysUserInfoDTO extends BaseDTO {
/** 用户ID */
userId?: string;
/** 头像 */
avatar?: string;
/** 性别 */
gender?: number;
/** 用户名称 */
username?: string;
/** 等级 */
level?: number;
/** 身份证号 */
idCard?: string;
/** 地址 */
address?: string;
}
// TbSysUserRoleDTO - 系统用户角色关系DTO
export interface TbSysUserRoleDTO extends BaseDTO {
/** 用户ID */
userId?: string;
/** 角色ID */
roleId?: string;
}

View File

@@ -0,0 +1 @@
export * from "./workcase"

View File

@@ -0,0 +1,279 @@
/**
* 工单服务相关 types - 根据后端 VO 和 DTO 转换
*/
import { BaseVO, BaseDTO } from "@/types/base"
// TicketVO - 工单详情
export interface TicketVO extends BaseVO {
/** 工单ID */
ticketId?: string
/** 工单编号 */
ticketNo?: string
/** 客户ID */
customerId?: string
/** 客户姓名 */
customerName?: string
/** 客户电话 */
customerPhone?: string
/** 关联会话ID */
conversationId?: string
/** 工单类型 */
ticketType?: string
/** 工单类型名称 */
ticketTypeName?: string
/** 工单分类 */
ticketCategory?: string
/** 优先级 */
priority?: string
/** 优先级名称 */
priorityName?: string
/** 优先级颜色 */
priorityColor?: string
/** 工单标题 */
title?: string
/** 问题描述 */
description?: string
/** 附件ID数组 */
attachments?: string[]
/** 附件数量 */
attachmentCount?: number
/** 工单来源 */
ticketSource?: string
/** 工单来源名称 */
ticketSourceName?: string
/** 分配给处理人ID */
assignedTo?: string
/** 处理人姓名 */
assignedToName?: string
/** 分配部门 */
assignedDept?: string
/** 分配部门名称 */
assignedDeptName?: string
/** 工单状态 */
ticketStatus?: string
/** 工单状态名称 */
ticketStatusName?: string
/** 工单状态颜色 */
statusColor?: string
/** 解决方案 */
resolution?: string
/** 解决时间 */
resolutionTime?: string
/** 关闭时间 */
closeTime?: string
/** 首次响应时间 */
responseTime?: string
/** SLA截止时间 */
slaDeadline?: string
/** 是否逾期 */
isOverdue?: boolean
/** 距离SLA截止的剩余时间分钟 */
slaRemainingMinutes?: number
/** 客户评分1-5星 */
customerRating?: number
/** 客户反馈 */
customerFeedback?: string
/** CRM系统工单ID */
crmTicketId?: string
/** 同步状态 */
syncStatus?: string
/** 同步状态名称 */
syncStatusName?: string
/** 工单标签 */
tags?: string[]
/** 工单元数据 */
metadata?: Record<string, any>
/** 处理记录数量 */
logCount?: number
/** 创建者姓名 */
creatorName?: string
/** 更新者姓名 */
updaterName?: string
}
// TicketListVO - 工单列表(简化版)
export interface TicketListVO extends BaseVO {
/** 工单ID */
ticketId?: string
/** 工单编号 */
ticketNo?: string
/** 客户姓名 */
customerName?: string
/** 工单标题 */
title?: string
/** 工单类型名称 */
ticketTypeName?: string
/** 优先级 */
priority?: string
/** 优先级名称 */
priorityName?: string
/** 工单状态 */
ticketStatus?: string
/** 工单状态名称 */
ticketStatusName?: string
/** 处理人姓名 */
assignedToName?: string
/** SLA截止时间 */
slaDeadline?: string
/** 是否逾期 */
isOverdue?: boolean
/** 创建者姓名 */
creatorName?: string
}
// TbTicketDTO - 工单DTO创建和更新
export interface TbTicketDTO extends BaseDTO {
/** 工单ID更新时需要 */
ticketId?: string
/** 工单编号 */
ticketNo?: string
/** 客户ID */
customerId?: string
/** 关联会话ID */
conversationId?: string
/** 工单类型 */
ticketType?: string
/** 工单分类 */
ticketCategory?: string
/** 优先级 */
priority?: string
/** 工单标题 */
title?: string
/** 问题描述 */
description?: string
/** 附件ID数组 */
attachments?: string[]
/** 工单来源 */
ticketSource?: string
/** 分配给(处理人) */
assignedTo?: string
/** 分配部门 */
assignedDept?: string
/** 工单状态 */
ticketStatus?: string
/** 解决方案 */
resolution?: string
/** 解决时间 */
resolutionTime?: string
/** 关闭时间 */
closeTime?: string
/** 首次响应时间 */
responseTime?: string
/** SLA截止时间 */
slaDeadline?: string
/** 是否逾期 */
isOverdue?: boolean
/** 客户评分1-5星 */
customerRating?: number
/** 客户反馈 */
customerFeedback?: string
/** CRM系统工单ID */
crmTicketId?: string
/** 同步状态 */
syncStatus?: string
/** 工单标签 */
tags?: string[]
/** 工单元数据 */
metadata?: Record<string, any>
}
// CustomerVO - 客户信息
export interface CustomerVO extends BaseVO {
/** 客户ID */
customerId?: string
/** 客户编号 */
customerNo?: string
/** 客户姓名 */
customerName?: string
/** 客户类型 */
customerType?: string
/** 公司名称 */
companyName?: string
/** 电话 */
phone?: string
/** 邮箱 */
email?: string
/** 微信OpenID */
wechatOpenid?: string
/** 微信UnionID */
wechatUnionid?: string
/** 头像URL */
avatar?: string
/** 性别 */
gender?: number
/** 地址 */
address?: string
/** 客户等级 */
customerLevel?: string
/** 客户来源 */
customerSource?: string
/** 客户标签数组 */
tags?: string[]
/** 备注 */
notes?: string
/** CRM系统客户ID */
crmCustomerId?: string
/** 最后联系时间 */
lastContactTime?: string
/** 咨询总次数 */
totalConsultations?: number
/** 订单总数 */
totalOrders?: number
/** 总消费金额 */
totalAmount?: number
/** 满意度评分1-5 */
satisfactionScore?: number
/** 状态 */
status?: string
}
// TbCustomerDTO - 客户DTO创建和更新
export interface TbCustomerDTO extends BaseDTO {
/** 客户ID更新时需要 */
customerId?: string
/** 客户编号 */
customerNo?: string
/** 客户姓名 */
customerName?: string
/** 客户类型 */
customerType?: string
/** 公司名称 */
companyName?: string
/** 电话 */
phone?: string
/** 邮箱 */
email?: string
/** 微信OpenID */
wechatOpenid?: string
/** 微信UnionID */
wechatUnionid?: string
/** 头像URL */
avatar?: string
/** 性别 */
gender?: number
/** 地址 */
address?: string
/** 客户等级 */
customerLevel?: string
/** 客户来源 */
customerSource?: string
/** 客户标签数组 */
tags?: string[]
/** 备注 */
notes?: string
/** CRM系统客户ID */
crmCustomerId?: string
/** 最后联系时间 */
lastContactTime?: string
/** 咨询总次数 */
totalConsultations?: number
/** 订单总数 */
totalOrders?: number
/** 总消费金额 */
totalAmount?: number
/** 满意度评分1-5 */
satisfactionScore?: number
/** 状态 */
status?: string
}

View File

@@ -0,0 +1,30 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["node"],
"jsx": "preserve",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"isolatedModules": true,
"noEmit": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": [
"src/**/*",
"vite.config.*.ts"
, "vite.config.ts" ],
"exclude": [
"node_modules",
"dist"
]
}

View File

@@ -1,7 +1,12 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx' import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve } from 'path' import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
// ES 模块中获取 __dirname
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
/** /**
* ES Module * ES Module
@@ -13,6 +18,13 @@ import { resolve } from 'path'
export default defineConfig({ export default defineConfig({
plugins: [vue(), vueJsx()], plugins: [vue(), vueJsx()],
resolve: {
alias: [
{ find: '@', replacement: resolve(__dirname, 'src') }
],
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
build: { build: {
lib: { lib: {
entry: { entry: {
@@ -78,7 +90,6 @@ export default defineConfig({
// 启用代码分割 // 启用代码分割
cssCodeSplit: true cssCodeSplit: true
}, },
// 开发服务器配置 // 开发服务器配置
server: { server: {
port: 5000, port: 5000,

View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="/favicon.ico">
<title>案例管理系统</title>
<!-- 加载运行时配置(必须在其他脚本之前加载) -->
<script src="/app-config.js"></script>
<!-- Import Maps 配置 - 引用共享模块 -->
<script type="importmap">
{
"imports": {
"@shared/components": "http://localhost:5000/shared/components.js",
"@shared/utils": "http://localhost:5000/shared/utils.js",
"@shared/api": "http://localhost:5000/shared/api.js",
"@shared/composables": "http://localhost:5000/shared/composables.js",
"@shared/types": "http://localhost:5000/shared/types.js"
}
}
</script>
<!-- 预加载关键模块 -->
<link rel="modulepreload" href="http://localhost:5000/shared/components.js">
<link rel="modulepreload" href="http://localhost:5000/shared/utils.js">
</head>
<body>
<div id="app"></div>
<!-- ES Module 入口 -->
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -0,0 +1,27 @@
{
"name": "@urbanlifeline/workcase",
"version": "1.0.0",
"type": "module",
"private": true,
"scripts": {
"dev": "vite --port 5003 --host",
"build": "vue-tsc && vite build",
"preview": "vite preview --port 5003"
},
"dependencies": {
"vue": "^3.5.13",
"vue-router": "^4.5.0",
"pinia": "^2.2.8",
"element-plus": "^2.9.1",
"@vueuse/core": "^11.3.0",
"axios": "^1.7.9"
},
"devDependencies": {
"@types/node": "^22.0.0",
"@vitejs/plugin-vue": "^5.2.1",
"@vitejs/plugin-vue-jsx": "^4.1.1",
"typescript": "^5.7.2",
"vite": "^6.0.3",
"vue-tsc": "^2.2.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/**
* @description 应用运行时配置文件
* @author yslg
* @since 2025-12-06
*
* 说明:
* 1. 此文件在生产环境中被加载,用于覆盖内置配置
* 2. Docker 部署时,可通过挂载此文件来修改配置,无需重新构建
* 3. 配置结构必须与 packages/shared/src/config/index.ts 中的 AppRuntimeConfig 保持一致
*
* 使用示例Docker
* docker run -v /path/to/app-config.js:/app/public/app-config.js my-app:latest
*/
window.APP_RUNTIME_CONFIG = {
// 环境标识
env: 'production',
// API 配置
api: {
baseUrl: '/api',
timeout: 30000
},
// 应用基础路径
baseUrl: '/',
// 文件配置
file: {
downloadUrl: '/api/file/download/',
uploadUrl: '/api/file/upload',
maxSize: {
image: 5, // MB
video: 100, // MB
document: 10 // MB
},
acceptTypes: {
image: 'image/*',
video: 'video/*',
document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx'
}
},
// Token 配置
token: {
key: 'token',
refreshThreshold: 300000 // 5分钟
},
// 公共资源路径
publicImgPath: '/img',
publicWebPath: '/',
// 功能开关
features: {
enableDebug: false,
enableMockData: false
}
};

View File

@@ -0,0 +1,32 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["node"],
"jsx": "preserve",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"isolatedModules": true,
"noEmit": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@shared/*": ["../shared/src/*"]
}
},
"include": [
"src/**/*",
"*.ts",
"*.vue"
],
"exclude": [
"node_modules",
"dist"
]
}

View File

@@ -0,0 +1,49 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
export default defineConfig({
plugins: [vue(), vueJsx()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
server: {
port: 5003,
host: true,
cors: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/api/, '')
},
// 代理共享模块请求到 shared 服务
'/shared': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
},
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'element-plus': ['element-plus']
}
}
}
}
})

357
urbanLifelineWeb/pnpm-lock.yaml generated Normal file
View File

@@ -0,0 +1,357 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
devDependencies:
concurrently:
specifier: ^9.1.0
version: 9.2.1
rimraf:
specifier: ^5.0.5
version: 5.0.10
packages:
/@isaacs/cliui@8.0.2:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
dependencies:
string-width: 5.1.2
string-width-cjs: /string-width@4.2.3
strip-ansi: 7.1.2
strip-ansi-cjs: /strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: /wrap-ansi@7.0.0
dev: true
/@pkgjs/parseargs@0.11.0:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
requiresBuild: true
dev: true
optional: true
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: true
/ansi-regex@6.2.2:
resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==}
engines: {node: '>=12'}
dev: true
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: true
/ansi-styles@6.2.3:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
dev: true
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
dependencies:
balanced-match: 1.0.2
dev: true
/chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
dev: true
/cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
dev: true
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: true
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/concurrently@9.2.1:
resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==}
engines: {node: '>=18'}
hasBin: true
dependencies:
chalk: 4.1.2
rxjs: 7.8.2
shell-quote: 1.8.3
supports-color: 8.1.1
tree-kill: 1.2.2
yargs: 17.7.2
dev: true
/cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
dev: true
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: true
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true
/emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
dev: true
/escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
dev: true
/foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
dev: true
/get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
dev: true
/glob@10.5.0:
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
hasBin: true
dependencies:
foreground-child: 3.3.1
jackspeak: 3.4.3
minimatch: 9.0.5
minipass: 7.1.2
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
dev: true
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: true
/is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
dev: true
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
dev: true
/lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
dev: true
/minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
brace-expansion: 2.0.2
dev: true
/minipass@7.1.2:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
dev: true
/package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
dev: true
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
dev: true
/path-scurry@1.11.1:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
dependencies:
lru-cache: 10.4.3
minipass: 7.1.2
dev: true
/require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
dev: true
/rimraf@5.0.10:
resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==}
hasBin: true
dependencies:
glob: 10.5.0
dev: true
/rxjs@7.8.2:
resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
dependencies:
tslib: 2.8.1
dev: true
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
dependencies:
shebang-regex: 3.0.0
dev: true
/shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
dev: true
/shell-quote@1.8.3:
resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==}
engines: {node: '>= 0.4'}
dev: true
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
dev: true
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
dev: true
/string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.2
dev: true
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: true
/strip-ansi@7.1.2:
resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
engines: {node: '>=12'}
dependencies:
ansi-regex: 6.2.2
dev: true
/supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
dev: true
/supports-color@8.1.1:
resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
engines: {node: '>=10'}
dependencies:
has-flag: 4.0.0
dev: true
/tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
dev: true
/tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
dev: true
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
dependencies:
isexe: 2.0.0
dev: true
/wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
dev: true
/wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
dependencies:
ansi-styles: 6.2.3
string-width: 5.1.2
strip-ansi: 7.1.2
dev: true
/y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
dev: true
/yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
dev: true
/yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
dependencies:
cliui: 8.0.1
escalade: 3.2.0
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
dev: true

View File

@@ -0,0 +1,2 @@
packages:
- 'packages/*'

View File

@@ -0,0 +1,16 @@
@echo off
echo ====================================
echo Urban Lifeline Web - 启动所有服务
echo ====================================
echo.
echo 端口分配:
echo Shared: http://localhost:5000
echo Platform: http://localhost:5001
echo Bidding: http://localhost:5002
echo Workcase: http://localhost:5003
echo.
echo 按 Ctrl+C 停止所有服务
echo ====================================
echo.
npm run dev:all