diff --git a/doc/requirement.sql b/doc/requirement.sql deleted file mode 100644 index 5147621..0000000 --- a/doc/requirement.sql +++ /dev/null @@ -1,34 +0,0 @@ --- 需求工单表 -CREATE TABLE IF NOT EXISTS `requirement` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键,需求ID', - `tenant_id` BIGINT NOT NULL COMMENT '租户ID', - `requirement_code` VARCHAR(50) NOT NULL COMMENT '需求编号', - `requirement_name` VARCHAR(200) NOT NULL COMMENT '需求名称', - `description` TEXT COMMENT '需求描述', - `project_id` BIGINT NOT NULL COMMENT '项目ID', - `customer_id` BIGINT NOT NULL COMMENT '客户ID', - `priority` VARCHAR(20) DEFAULT 'normal' COMMENT '优先级:high-高,normal-中,low-低', - `estimated_hours` DECIMAL(8,2) DEFAULT 0.00 COMMENT '预估开发工时(小时)', - `actual_hours` DECIMAL(8,2) DEFAULT 0.00 COMMENT '实际开发工时(小时)', - `planned_start` DATE COMMENT '计划开始日期', - `planned_end` DATE COMMENT '计划结束日期', - `actual_start` DATE COMMENT '实际开始日期', - `actual_end` DATE COMMENT '实际结束日期', - `delivery_date` DATE COMMENT '交付日期', - `receivable_amount` DECIMAL(15,2) DEFAULT 0.00 COMMENT '应收款金额', - `receivable_date` DATE COMMENT '应收款日期', - `status` VARCHAR(20) DEFAULT 'pending' COMMENT '状态:pending-待开发,developing-开发中,delivered-已交付,completed-已完成', - `progress` INT DEFAULT 0 COMMENT '开发进度(0-100)', - `attachment_url` VARCHAR(500) COMMENT '附件URL', - `created_by` BIGINT COMMENT '创建人ID', - `created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` BIGINT COMMENT '更新人ID', - `updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除:0-未删除,1-已删除', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_tenant_code` (`tenant_id`, `requirement_code`), - INDEX `idx_tenant` (`tenant_id`), - INDEX `idx_project` (`project_id`), - INDEX `idx_customer` (`customer_id`), - INDEX `idx_status` (`status`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='需求工单表'; diff --git a/doc/sql/fund_exp_init.sql b/doc/sql/fund_exp_init.sql index 4a74dd9..9959cce 100644 --- a/doc/sql/fund_exp_init.sql +++ b/doc/sql/fund_exp_init.sql @@ -22,6 +22,7 @@ CREATE TABLE IF NOT EXISTS expense_type ( sort_order INT DEFAULT 0 COMMENT '排序号', description VARCHAR(500) COMMENT '类型描述', status TINYINT NOT NULL DEFAULT 1 COMMENT '状态: 0-禁用, 1-启用', + remark VARCHAR(500) COMMENT '备注', created_by BIGINT COMMENT '创建人', created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', updated_by BIGINT COMMENT '更新人', diff --git a/doc/sql/fund_proj_init.sql b/doc/sql/fund_proj_init.sql index 08c00a1..eec4532 100644 --- a/doc/sql/fund_proj_init.sql +++ b/doc/sql/fund_proj_init.sql @@ -1,8 +1,9 @@ -- ============================================= -- 资金服务平台 - 项目管理数据库初始化脚本 -- Database: fund_proj --- Version: 1.0 +-- Version: 1.1 -- Created: 2026-02-17 +-- Updated: 2026-02-22 (添加requirement表) -- ============================================= CREATE DATABASE IF NOT EXISTS fund_proj DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; @@ -38,6 +39,43 @@ CREATE TABLE IF NOT EXISTS project ( KEY idx_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='项目表'; +-- ============================================= +-- 2. 需求工单表 (requirement) +-- ============================================= +CREATE TABLE IF NOT EXISTS requirement ( + id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键,需求ID', + tenant_id BIGINT NOT NULL COMMENT '租户ID', + requirement_code VARCHAR(50) NOT NULL COMMENT '需求编号', + requirement_name VARCHAR(200) NOT NULL COMMENT '需求名称', + description TEXT COMMENT '需求描述', + project_id BIGINT NOT NULL COMMENT '项目ID', + customer_id BIGINT NOT NULL COMMENT '客户ID', + priority VARCHAR(20) DEFAULT 'normal' COMMENT '优先级:high-高,normal-中,low-低', + estimated_hours DECIMAL(8,2) DEFAULT 0.00 COMMENT '预估开发工时(小时)', + actual_hours DECIMAL(8,2) DEFAULT 0.00 COMMENT '实际开发工时(小时)', + planned_start DATE COMMENT '计划开始日期', + planned_end DATE COMMENT '计划结束日期', + actual_start DATE COMMENT '实际开始日期', + actual_end DATE COMMENT '实际结束日期', + delivery_date DATE COMMENT '交付日期', + receivable_amount DECIMAL(15,2) DEFAULT 0.00 COMMENT '应收款金额', + receivable_date DATE COMMENT '应收款日期', + status VARCHAR(20) DEFAULT 'pending' COMMENT '状态:pending-待开发,developing-开发中,delivered-已交付,completed-已完成', + progress INT DEFAULT 0 COMMENT '开发进度(0-100)', + attachment_url VARCHAR(500) COMMENT '附件URL', + created_by BIGINT COMMENT '创建人ID', + created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + updated_by BIGINT COMMENT '更新人ID', + updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + deleted TINYINT DEFAULT 0 COMMENT '逻辑删除:0-未删除,1-已删除', + PRIMARY KEY (id), + UNIQUE KEY uk_tenant_code (tenant_id, requirement_code), + KEY idx_tenant (tenant_id), + KEY idx_project (project_id), + KEY idx_customer (customer_id), + KEY idx_status (status) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='需求工单表'; + -- ============================================= -- 初始化测试数据(租户ID=1) -- ============================================= diff --git a/doc/sql/fund_sys_init.sql b/doc/sql/fund_sys_init.sql index d767384..59b1986 100644 --- a/doc/sql/fund_sys_init.sql +++ b/doc/sql/fund_sys_init.sql @@ -177,12 +177,17 @@ CREATE TABLE IF NOT EXISTS sys_dict ( -- ============================================= CREATE TABLE IF NOT EXISTS sys_config ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT '配置ID', + tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', config_key VARCHAR(128) NOT NULL COMMENT '配置键', config_value TEXT COMMENT '配置值', config_type VARCHAR(64) DEFAULT 'string' COMMENT '配置类型: string/number/boolean/json', description VARCHAR(500) COMMENT '配置描述', is_system TINYINT NOT NULL DEFAULT 0 COMMENT '是否系统配置: 0-否, 1-是(系统配置不参与多租户隔离)', status TINYINT NOT NULL DEFAULT 1 COMMENT '状态: 0-禁用, 1-启用', + group_code VARCHAR(64) COMMENT '分组编码', + group_name VARCHAR(128) COMMENT '分组名称', + sort_order INT DEFAULT 0 COMMENT '排序号', + remark VARCHAR(500) COMMENT '备注', created_by BIGINT COMMENT '创建人', created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', updated_by BIGINT COMMENT '更新人', @@ -190,7 +195,8 @@ CREATE TABLE IF NOT EXISTS sys_config ( deleted TINYINT NOT NULL DEFAULT 0 COMMENT '删除标记: 0-未删除, 1-已删除', PRIMARY KEY (id), UNIQUE KEY uk_config_key (config_key, deleted), - KEY idx_status (status) + KEY idx_status (status), + KEY idx_group_code (group_code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统配置表(不参与租户隔离)'; -- ============================================= diff --git a/doc/数据库设计文档.md b/doc/数据库设计文档.md index 45317b5..a088c67 100644 --- a/doc/数据库设计文档.md +++ b/doc/数据库设计文档.md @@ -1,7 +1,7 @@ # 资金服务平台数据库设计文档 -> 版本: v1.0 -> 更新日期: 2026-02-13 +> 版本: v1.1 +> 更新日期: 2026-02-22 > 作者: zhangjf > 数据库: MySQL 8.0 > 字符集: utf8mb4 @@ -705,6 +705,98 @@ | updated_time | DATETIME | 更新时间(DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) | | deleted | TINYINT | 逻辑删除标志(DEFAULT 0) | +### 4.4 实体类与SQL脚本同步规范 + +> **强制要求**:修改实体类字段时,必须同步更新 SQL 初始化脚本 + +#### 4.4.1 同步修改流程 + +```mermaid +graph LR + A[修改实体类字段] --> B[同步修改SQL脚本] + B --> C[更新数据库设计文档] + C --> D[编译验证] + D --> E[提交代码] +``` + +| 操作类型 | 实体类修改 | SQL脚本修改 | 文档更新 | +|----------|------------|-------------|----------| +| 新增字段 | 添加属性 + Getter/Setter | ALTER TABLE ADD COLUMN | 更新表结构说明 | +| 删除字段 | 删除属性 + Getter/Setter | ALTER TABLE DROP COLUMN | 更新表结构说明 | +| 修改字段 | 修改属性类型 | ALTER TABLE MODIFY COLUMN | 更新字段说明 | +| 新增实体 | 创建Entity类 | CREATE TABLE | 新增表结构说明 | + +#### 4.4.2 常见问题与预防 + +| 问题 | 原因 | 预防措施 | +|------|------|----------| +| Unknown column | 实体类有字段但数据库表无对应列 | 修改实体类后立即更新SQL脚本 | +| SQLSyntaxErrorException | SQL脚本与实体类不一致 | 提交前对比验证 | +| 字段类型不匹配 | Java类型与MySQL类型映射错误 | 参照4.2字段规范 | + +#### 4.4.3 Java与MySQL类型映射 + +| Java类型 | MySQL类型 | 说明 | +|----------|-----------|------| +| Long | BIGINT | 主键、外键、ID | +| String | VARCHAR(n) | 根据长度选择n值 | +| String (长文本) | TEXT | 超过500字符 | +| Integer | INT | 数量、排序 | +| Boolean / Integer | TINYINT | 0/1状态值 | +| BigDecimal | DECIMAL(15,2) | 金额 | +| LocalDateTime | DATETIME | 日期时间 | +| LocalDate | DATE | 日期 | + +### 4.5 自动化检查机制 + +#### 4.5.1 单元测试验证 + +建议在 `fund-common` 或各业务模块的测试目录中添加实体类与表结构一致性测试: + +```java +@SpringBootTest +class EntitySchemaConsistencyTest { + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Test + @DisplayName("验证SysConfig实体类与sys_config表结构一致") + void testSysConfigSchema() { + // 获取数据库表结构 + var columns = jdbcTemplate.queryForList( + "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS " + + "WHERE TABLE_NAME = 'sys_config' AND TABLE_SCHEMA = DATABASE()" + ); + Set dbColumns = columns.stream() + .map(row -> (String) row.get("COLUMN_NAME")) + .collect(Collectors.toSet()); + + // 获取实体类字段(通过反射) + Set entityFields = Arrays.stream(SysConfig.class.getDeclaredFields()) + .map(f -> CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, f.getName())) + .collect(Collectors.toSet()); + + // 验证一致性 + assertThat(entityFields).isSubsetOf(dbColumns); + } +} +``` + +#### 4.5.2 CI/CD集成检查 + +在持续集成流程中添加数据库脚本验证步骤: + +```yaml +# .gitlab-ci.yml 或 GitHub Actions +validate-schema: + stage: test + script: + - echo "验证SQL脚本语法" + - mysql --help > /dev/null 2>&1 && echo "MySQL client available" + # 可集成sqlfluff等SQL语法检查工具 +``` + --- **文档结束** diff --git a/fund-admin/.env.development b/fund-admin/.env.development new file mode 100644 index 0000000..68e9a47 --- /dev/null +++ b/fund-admin/.env.development @@ -0,0 +1,6 @@ +# 开发环境配置 +# 开发模式无部署前缀 +VITE_BASE=/ + +# API基础路径(开发模式使用代理) +VITE_API_BASE_URL= diff --git a/fund-admin/.env.production b/fund-admin/.env.production new file mode 100644 index 0000000..322609b --- /dev/null +++ b/fund-admin/.env.production @@ -0,0 +1,6 @@ +# 生产环境配置 +# 部署路径前缀(Nginx路由使用) +VITE_BASE=/fadmin/ + +# API基础路径 +VITE_API_BASE_URL=/fund diff --git a/fund-admin/src/api/request.ts b/fund-admin/src/api/request.ts index 109db53..58942d8 100644 --- a/fund-admin/src/api/request.ts +++ b/fund-admin/src/api/request.ts @@ -3,7 +3,7 @@ import { ElMessage } from 'element-plus' // 创建axios实例 const service: AxiosInstance = axios.create({ - baseURL: '/fund', + baseURL: import.meta.env.VITE_API_BASE_URL || '/fund', timeout: 15000, headers: { 'Content-Type': 'application/json' diff --git a/fund-admin/src/router/index.ts b/fund-admin/src/router/index.ts index 6902925..dc23b42 100644 --- a/fund-admin/src/router/index.ts +++ b/fund-admin/src/router/index.ts @@ -134,7 +134,7 @@ const routes: RouteRecordRaw[] = [ ] const router = createRouter({ - history: createWebHistory(), + history: createWebHistory(import.meta.env.BASE_URL), routes }) diff --git a/fund-admin/vite.config.ts b/fund-admin/vite.config.ts index 85c2bec..fe75bc9 100644 --- a/fund-admin/vite.config.ts +++ b/fund-admin/vite.config.ts @@ -1,53 +1,61 @@ -import { defineConfig } from 'vite' +import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'path' // https://vite.dev/config/ -export default defineConfig({ - plugins: [vue()], - resolve: { - alias: { - '@': path.resolve(__dirname, 'src') - } - }, - server: { - port: 3000, - proxy: { - '/auth/': { - target: 'http://localhost:8100', - changeOrigin: true - }, - '/sys/': { - target: 'http://localhost:8000', - changeOrigin: true - }, - '/cust/': { - target: 'http://localhost:8000', - changeOrigin: true - }, - '/proj/': { - target: 'http://localhost:8000', - changeOrigin: true - }, - '/req/': { - target: 'http://localhost:8000', - changeOrigin: true - }, - '/exp/': { - target: 'http://localhost:8000', - changeOrigin: true - }, - '/receipt/': { - target: 'http://localhost:8000', - changeOrigin: true - }, - '/file/': { - target: 'http://localhost:8000', - changeOrigin: true - }, - '/report/': { - target: 'http://localhost:8000', - changeOrigin: true +export default defineConfig(({ mode }) => { + // 加载环境变量 + const env = loadEnv(mode, process.cwd()) + const base = env.VITE_BASE || '/' + + return { + // 部署路径前缀 + base, + plugins: [vue()], + resolve: { + alias: { + '@': path.resolve(__dirname, 'src') + } + }, + server: { + port: 3000, + proxy: { + '/auth/': { + target: 'http://localhost:8100', + changeOrigin: true + }, + '/sys/': { + target: 'http://localhost:8000', + changeOrigin: true + }, + '/cust/': { + target: 'http://localhost:8000', + changeOrigin: true + }, + '/proj/': { + target: 'http://localhost:8000', + changeOrigin: true + }, + '/req/': { + target: 'http://localhost:8000', + changeOrigin: true + }, + '/exp/': { + target: 'http://localhost:8000', + changeOrigin: true + }, + '/receipt/': { + target: 'http://localhost:8000', + changeOrigin: true + }, + '/file/': { + target: 'http://localhost:8000', + changeOrigin: true + }, + '/report/': { + target: 'http://localhost:8000', + changeOrigin: true + } } } } diff --git a/scripts/deploy-frontend-nginx.sh b/scripts/deploy-frontend-nginx.sh index ca025bd..5f88e56 100755 --- a/scripts/deploy-frontend-nginx.sh +++ b/scripts/deploy-frontend-nginx.sh @@ -70,11 +70,28 @@ generate_nginx_conf() { local project_name=$1 local gateway_host=$2 local output_file=$3 + local location_prefix=$4 # 部署路径前缀,如 /fadmin + + # 根据项目名确定部署前缀 + if [ -z "${location_prefix}" ]; then + case "${project_name}" in + "fund-admin") + location_prefix="/fadmin" + ;; + "fund-mobile") + location_prefix="/fmobile" + ;; + *) + location_prefix="" + ;; + esac + fi cat > "${output_file}" << EOF # ${project_name} Nginx配置 # 生成时间: $(date '+%Y-%m-%d %H:%M:%S') # 网关地址: ${gateway_host} +# 部署路径: ${location_prefix} server { listen 80; @@ -112,27 +129,11 @@ server { # 文件上传大小限制 client_max_body_size 100m; } - - # 兼容旧版/api代理(可选,逐步迁移后可删除) - location /api/ { - proxy_pass http://${gateway_host}/; - proxy_set_header Host \$host; - proxy_set_header X-Real-IP \$remote_addr; - proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto \$scheme; - - # 超时配置 - proxy_connect_timeout 60s; - proxy_send_timeout 60s; - proxy_read_timeout 60s; - - # 文件上传大小限制 - client_max_body_size 100m; - } # Vue Router History模式支持 - location / { - try_files \$uri \$uri/ /index.html; + location ${location_prefix}/ { + alias /usr/share/nginx/html/; + try_files \$uri \$uri/ ${location_prefix}/index.html; } # 安全头