This commit is contained in:
2026-02-09 17:25:22 +08:00
12 changed files with 3617 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
{
"source": "local",
"sourceType": "local",
"installedAt": "2026-01-22T09:00:00.000Z"
}
+413
View File
@@ -0,0 +1,413 @@
---
name: g3fo-db-ops
description: Comprehensive database operations guide for G3FO project. Use when updating G3FO database data, creating tables, modifying table structures, inserting system menus/routes, or managing database changes that require SQL generation, execution, and Git commit workflows. Includes automated workflows for i18n updates, version management, file naming conventions, and duplicate sequence number detection.
---
# G3FO Database Operations
Guide for performing database operations in the G3FO project, including automated workflows for data updates, table management, and SQL file versioning.
**Detailed documentation**: See `references/DATABASE_UPDATE_AUTOMATION_GUIDE.md` for complete automation guide.
## Core Principles
1. **Use existing templates**: Prioritize templates and tools in `g3fo-db/common_sql/`
2. **Update i18n simultaneously**: When updating tables requiring multilingual support, must also update `m_system_i18n` table
3. **Automated workflow**: Follow standardized automation including SQL generation, execution, and Git commit
## Tables Requiring i18n Updates
When inserting or updating data in these tables, must simultaneously update `m_system_i18n`:
| Table | i18n_id Format | Example |
|-------|---------------|---------|
| `m_system_code` | `CODE-{4位数字ID}` | `CODE-0404` |
| `m_system_error_message` | `ERR-{error_code}` | `ERR-17100` |
| `m_market` | `MKT-{4位数字ID}` | `MKT-0001` |
| `m_currency` | `CURR-{currency_code}` | `CURR-USD` |
| `m_channel` | `CH-{channel_code}` | `CH-001` |
| `m_exchange` | `EXCH-{exchange_code}` | `EXCH-HKEX` |
| `m_country` | `CNTY-{country_code}` | `CNTY-HK` |
| `m_exchange_charge` | `EX_CHARGE-{id}` | `EX_CHARGE-1` |
| `m_company_charge` | `COM_CHARGE-{id}` | `COM_CHARGE-1` |
## Automated Workflow
### 1. Data Input Phase
Request user input based on table type. For `m_system_code`:
- Code_type: [编码类型]
- Code_value: [编码值]
- Remark: [备注(用于生成多语言描述)]
- Sort: [排序号]
### 2. SQL Generation Phase
1. **Get max ID** (if applicable):
```sql
SELECT COALESCE(MAX(id), 0) + 1 FROM {schema}.{table_name};
```
2. **Generate i18n_id**: Use format rules based on table type
3. **Generate multilingual descriptions**:
- Extract or generate English, Simplified Chinese, Traditional Chinese from remark
- Vietnamese and French optional
4. **Generate complete SQL**:
- Main table INSERT/UPDATE
- m_system_i18n INSERT/UPDATE (if applicable)
### 3. User Confirmation Phase
Display generated SQL and ask:
```
已生成以下 SQL 语句,请确认数据是否正确:
[显示SQL语句]
确认数据无误,是否继续下一步?(yes/no)
```
### 4. SQL Execution Phase
If user confirms:
1. Connect to database using MySQL MCP
- **Default database connection** (automatically use when MySQL MCP or database connection is needed):
- host: 192.168.3.233
- user: root
- password: afe123456
- database: g3fo_base (for system tables like m_system_code, m_system_i18n, m_system_error_message, etc.)
- database: g3fo_trade (for trade-related tables)
2. Execute SQL
3. Verify results
4. If failed, report error and stop
### 5. Git Commit Phase
After successful execution, ask:
```
SQL 执行成功!
是否需要将 SQL 提交到待执行文件夹中?(yes/no)
```
If confirmed, **execute in this order** to ensure remote repository and local data consistency:
1. **Switch to g3fo-db directory and pull latest code** (must execute first):
```bash
cd g3fo-db
git pull origin main
```
- This step ensures getting latest file list and changes from remote repository
- **If pull fails** (e.g., conflicts), report error and stop workflow
2. **Determine target folder** (based on latest pulled code):
- Find latest "pending release {version}" folder in `update_service_release`
- **If not exists, create new folder**:
- View all version number folders in `update_service_release` (e.g., `1.5.1.0`, `1.5.1.1`, `1.5.1.17`, etc.)
- Find maximum version number
- New version = max version + 0.0.0.1 (increment last digit)
- Create folder: `pending release {新版本号}`
- **Auto-create `set_version_01.sql`**:
```sql
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '1.5.1.0 M{版本号最后两位数字}',
`update_on` = NOW()
WHERE
`param_name` = 'base.systemVersion';
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '0',
`update_on` = NOW()
WHERE
`param_name` = 'base.patchNo';
```
- **Version mapping rules**:
- Extract last digit N from version number (format X.Y.Z.N)
- Format as `'1.5.1.0 M{N}'`
- Examples:
- `1.5.1.17` → extract `17` → `'1.5.1.0 M17'`
- `1.5.1.18` → extract `18` → `'1.5.1.0 M18'`
- `1.5.1.10` → extract `10` → `'1.5.1.0 M10'`
- `1.5.1.9` → extract `9` → `'1.5.1.0 M9'` (no zero padding)
- **Note**: Folder list is now latest, avoiding filename conflicts
3. **Generate filename** (based on latest file list):
- Format: `{功能描述英文}_{序号}.sql`
- Sequence number rules:
- View **all** `.sql` files in target folder (after git pull)
- **Calculate sequence number across all files uniformly**, regardless of filename prefix
- **Extract sequence number method**:
1. Traverse all `.sql` files in folder
2. Extract two-digit number after underscore from each filename (format: `_XX.sql`)
3. Example: `set_version_01.sql` → extract `01`, `add_system_code_02.sql` → extract `02`
4. Find **maximum** sequence number among all
5. New sequence = max + 1
- Use two-digit format (01-99)
- **Example**:
- If folder has: `set_version_01.sql` and `add_system_code_02.sql`
- Extracted sequences: `01`, `02`
- Max sequence: `02`
- New file sequence: `03`
- New filename: `add_new_feature_03.sql`
- **Important**: Must generate after git pull to avoid conflicts
4. **Detect and fix duplicate sequence numbers** (before saving):
- Scan all `.sql` files in target folder
- Detect duplicates
- If found, follow "Duplicate Sequence Detection and Auto-Fix" rules
- Ensure all file sequences are unique and continuous
5. **Save SQL file** to target folder
6. **Git commit and push**:
```bash
git add .
git commit -m "feat: {简短描述}"
git push origin main
```
**If push fails** (remote has new commits):
- Execute `git pull origin main` again
- Resolve conflicts and push again
### 6. Completion Message
```
操作完成!
已执行的操作:
✓ SQL 语句已执行
✓ SQL 文件已保存到: update_service_release/pending release {version}/{filename}
✓ 已推送到 Git 仓库
```
## Using Existing Templates
### Insert System Menu and Route Permissions
**Important: Adding menus and route permissions must use stored procedure files from `common_sql` folder.**
**Files to use:**
- `references/insert_system_menu_procedure.sql` - Insert system menu
- `references/insert_system_route_procedure.sql` - Insert system route
**Execution and commit rules:**
1. **SQL execution phase**:
- MySQL MCP doesn't support `DELIMITER` for stored procedures
- Can use direct `INSERT INTO` or `REPLACE INTO` to insert same data
- Ensure data matches stored procedure output exactly
2. **Git commit phase**:
- **Must use complete SQL from stored procedure file**
- Copy full stored procedure definition from `common_sql` folder
- Add `CALL` statement at end to invoke procedure
- Reference format in `update_service_release/pending release 1.5.1.18`
**Insert system menu example:**
```sql
-- Copy complete stored procedure definition from insert_system_menu_procedure.sql
-- ... (complete stored procedure code) ...
-- Add CALL statement at end
CALL InsertSystemMenu('菜单备注', 'menu-name', 'title_remark', 'ADMIN', NULL, 1);
```
**Insert system route example:**
```sql
-- Copy complete stored procedure definition from insert_system_route_procedure.sql
-- ... (complete stored procedure code) ...
-- Add CALL statement at end
CALL InsertSystemRoute('备注', '/route/path', '标题备注', 'ADMIN'|'USER');
```
**File naming:**
- Menu: `insert_system_menu_procedure_{序号}.sql`
- Route: `insert_system_route_procedure_{序号}.sql`
### Create New Table
Reference `references/create_table_template.sql` format:
- Use `CREATE TABLE IF NOT EXISTS`
- Specify correct schema (e.g., `g3fo_trade`, `g3fo_base`)
- Include necessary fields, indexes, comments
- Use `ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`
### Table Structure Changes
Reference `references/table_change_template.sql` method:
- Use stored procedure to check if column exists
- Use `IF EXISTS` for idempotency checks
- Delete procedure after execution
### Order Table Field Synchronization Rule
**Important: When `m_order` table adds a field, must simultaneously add same field to:**
1. `m_order_actions` - Order actions table
2. `h_order` - Order history table
3. `h_order_actions` - Order actions history table
**Rules:**
- Field name must be identical
- Field type must be identical
- Field constraints (NULL/NOT NULL, DEFAULT, etc.) must be identical
- Field comment must be identical
- Field position (AFTER clause) should be consistent
**SQL generation requirements:**
- Use stored procedure for idempotency checks (reference `table_change_template.sql`)
- Check field existence for each table separately, add if not exists
- Ensure all four tables' field changes in same SQL file
**Example:**
If need to add field `new_field VARCHAR(100) COMMENT '新字段'` to `m_order` table, must simultaneously add same field to `m_order_actions`, `h_order`, `h_order_actions` tables.
## SQL Statement Standards
1. **Use REPLACE INTO** instead of INSERT INTO for idempotency
2. **Timestamp fields**:
- `create_on`: `NOW()`
- `update_on`: `NOW()`
- `create_by`: `'sys'`
- `update_by`: `'sys'`
3. **Add comments**: Add function description comment at SQL file beginning
## File Naming Standards
- Format: `{功能描述英文}_{序号}.sql`
- Sequence: Two-digit number (01-99), auto-increment
- Examples: `add_system_code_02.sql`, `update_system_code_03.sql`
## Duplicate Sequence Detection and Auto-Fix
**Important: Must detect and fix duplicate sequence numbers before generating new files or committing to Git**
### Detection Rules
1. **Scan target folder**: Check all `.sql` files in `update_service_release/pending release {version}/`
2. **Extract sequence**: Extract two-digit number after underscore from each filename
3. **Detect duplicates**: If multiple files use same sequence, trigger fix flow
### Fix Rules
When duplicate sequences found (e.g., `xxxxxx_03.sql` and `aaaaaaa_03.sql`):
1. **Analyze file dependencies**:
- Compare SQL content of both files
- Check for dependencies:
- File A references table/field/data created in File B
- File A uses stored procedure/function defined in File B
- File A updates data inserted in File B
- **Dependency detection methods**:
- Check if table names, field names, or data values in one file appear in another file
- Check if CREATE/DROP operations in one file have corresponding references in another file
- Check if INSERT/UPDATE operations in one file have corresponding queries in another file
2. **Determine file order**:
- **If dependencies exist**:
- Dependent file (referenced) keeps original sequence
- Dependent file gets next available sequence
- **If no dependencies**:
- Order by file creation time (filesystem time)
- Earlier file keeps original sequence
- Later file gets next available sequence
3. **Auto-extend subsequent files**:
- Find next available sequence (max + 1)
- Rename file needing adjustment to new sequence
- **Check if subsequent files need extension**:
- If new sequence conflicts with subsequent files, auto-extend them
- Recursively process until no conflicts
4. **Execute fix**:
- Rename files (use `git mv` to preserve Git history)
- Update Git index
- Generate fix report
### Fix Examples
**Scenario 1: With dependencies**
- Files: `create_table_03.sql` (creates table `m_new_table`), `insert_data_03.sql` (inserts data into `m_new_table`)
- Detection: `insert_data_03.sql` depends on `create_table_03.sql`
- Fix:
- `create_table_03.sql` keeps `03`
- `insert_data_03.sql` → `insert_data_04.sql`
**Scenario 2: No dependencies, order by creation time**
- Files: `add_system_code_03.sql` (created: 2024-01-01), `update_setting_03.sql` (created: 2024-01-02)
- Detection: No dependencies
- Fix:
- `add_system_code_03.sql` keeps `03` (earlier)
- `update_setting_03.sql` → `update_setting_04.sql` (later)
**Scenario 3: Need to extend subsequent files**
- Files: `file_a_03.sql`, `file_b_03.sql`, `file_c_04.sql`, `file_d_05.sql`
- Detection: `file_a_03.sql` and `file_b_03.sql` duplicate, no dependencies, `file_a_03.sql` earlier
- Fix:
- `file_a_03.sql` keeps `03`
- `file_b_03.sql` → `file_b_04.sql`
- `file_c_04.sql` → `file_c_05.sql` (extended)
- `file_d_05.sql` → `file_d_06.sql` (extended)
**Scenario 4: Multiple duplicate sequences**
- Files: `file_a_03.sql`, `file_b_03.sql`, `file_c_04.sql`, `file_d_04.sql`, `file_e_05.sql`
- Detection: `03` duplicate, `04` also duplicate
- Fix:
- First handle `03` duplicate: `file_a_03.sql` keeps `03`, `file_b_03.sql` → `file_b_04.sql`
- Then handle `04` duplicate: `file_c_04.sql` keeps `04`, `file_d_04.sql` → `file_d_05.sql`
- Extend: `file_e_05.sql` → `file_e_06.sql`
### Fix Report Format
After fix completion, generate report:
```
检测到重复序号,已自动修复:
修复的文件:
- file_b_03.sql → file_b_04.sql(原因:与 file_a_03.sql 重复,无依赖关系,按创建时间调整)
- file_c_04.sql → file_c_05.sql(原因:序号冲突,自动顺延)
- file_d_05.sql → file_d_06.sql(原因:序号冲突,自动顺延)
所有文件序号已修复,无重复。
```
### Execution Timing
- **Before generating new file**: Detect and fix existing duplicate sequences
- **Before committing to Git**: Detect and fix again, ensure no duplicates
- **Manual trigger**: When user requests detection and fix
## Error Handling
- **SQL execution failure**: Display error, don't execute Git operations
- **Git operation failure**: Display error, SQL file saved locally
- **Data validation failure**: Validate data format before generating SQL
## Important Reminders
1. All table operations requiring i18n must simultaneously update `m_system_i18n` table
2. **When `m_order` table adds field, must simultaneously add same field to `m_order_actions`, `h_order`, `h_order_actions`**
3. **When adding menus and route permissions, execution can use other methods, but Git commit must use complete SQL from stored procedure file**
4. All SQL files must be saved to correct version folder
5. **File sequences cannot be duplicated, must be incremental. Must detect and fix duplicates before generating new files and committing to Git**
6. Use REPLACE INTO to ensure SQL can be executed repeatedly
7. Must get user confirmation before executing SQL
## Continuous Improvement
This workflow is continuously updated and improved. If new tables requiring i18n are discovered, new naming conventions are needed, or process issues are found, update the `DATABASE_UPDATE_AUTOMATION_GUIDE.md` document.
## Reference Files
For detailed templates and examples, see:
- `references/DATABASE_UPDATE_AUTOMATION_GUIDE.md` - Complete automation guide
- `references/create_table_template.sql` - Table creation template
- `references/table_change_template.sql` - Table structure change template
- `references/insert_system_menu_procedure.sql` - System menu insertion procedure
- `references/insert_system_route_procedure.sql` - System route insertion procedure
- `references/system_code_update_template.sql` - System code update template
- `references/SQL_SITE_NAMING.md` - SQL site naming conventions
@@ -0,0 +1,879 @@
# G3FO 数据库更新自动化流程指南
## 概述
本文档定义了使用 Cursor 更新 G3FO 项目数据库数据的标准自动化流程。当需要更新数据库时,系统会自动生成 SQL 语句文件并更新到 `g3fo-db` 仓库中。
## 目录结构
```
g3fo-db/
├── common_sql/ # 通用SQL模板和工具
│ ├── insert_system_route_procedure.sql # 插入系统路由存储过程
│ ├── create_table_template.sql # 创建表模板
│ ├── system_code_update_template.sql # 系统代码更新模板
│ ├── table_change_template.sql # 表结构变更模板
│ └── DATABASE_UPDATE_AUTOMATION_GUIDE.md # 本文档
└── update_service_release/ # 版本发布SQL文件夹
└── pending release {version}/ # 待执行SQL文件夹(最新版本)
```
## 一、使用现有模板和工具
### 1.1 插入系统菜单和路径权限
**重要规则:增加菜单和路径权限必须使用 `common_sql` 文件夹中的存储过程文件。**
**使用的文件:**
- `g3fo-db/common_sql/insert_system_menu_procedure.sql` - 插入系统菜单
- `g3fo-db/common_sql/insert_system_route_procedure.sql` - 插入系统路由
**执行和提交规则:**
#### 执行 SQL 阶段
由于 MySQL MCP 不支持使用 `DELIMITER` 的存储过程,执行时可以使用其他方法插入或更新相同的数据:
1. **使用直接的 INSERT/REPLACE 语句**:
- 使用 `INSERT INTO` 或 `REPLACE INTO` 语句直接插入数据
- 确保数据与存储过程生成的数据完全一致
- 需要手动处理 ID 生成、权限记录创建等逻辑
2. **数据一致性要求**:
- 菜单数据必须插入到 `m_system_menus` 表
- 路由数据必须插入到 `m_system_routes` 表
- 相应的权限记录必须插入到 `m_admin_role_rights` 或 `m_user_role_rights` 表
- 所有数据必须与存储过程生成的数据完全一致
#### 提交到 Git 阶段
**必须使用存储过程文件生成的完整 SQL:**
1. **从模板文件复制**:
- 从 `g3fo-db/common_sql/insert_system_menu_procedure.sql` 复制完整的存储过程定义
- 或从 `g3fo-db/common_sql/insert_system_route_procedure.sql` 复制完整的存储过程定义
2. **添加 CALL 语句**:
- 在文件末尾添加 `CALL` 语句来调用存储过程
- 参考 `update_service_release/pending release 1.5.1.18` 中的文件格式
3. **文件格式示例**:
**插入系统菜单:**
```sql
USE g3fo_base;
-- ===================================================================
-- 存储过程:插入系统菜单数据
-- ... (完整的存储过程定义,从 insert_system_menu_procedure.sql 复制) ...
-- ===================================================================
DROP PROCEDURE IF EXISTS InsertSystemMenu;
DELIMITER $$
CREATE PROCEDURE InsertSystemMenu(...)
BEGIN
-- ... 存储过程代码 ...
END$$
DELIMITER ;
-- ===================================================================
-- 在这里添加需要插入的菜单
-- ===================================================================
CALL InsertSystemMenu('菜单备注', 'menu-name', 'title_remark', 'ADMIN', NULL, 1);
CALL InsertSystemMenu('菜单备注2', 'menu-name-2', 'title_remark', 'USER', NULL, 1);
```
**插入系统路由:**
```sql
USE g3fo_base;
-- ===================================================================
-- 存储过程:插入系统路由数据
-- ... (完整的存储过程定义,从 insert_system_route_procedure.sql 复制) ...
-- ===================================================================
DROP PROCEDURE IF EXISTS InsertSystemRoute;
DELIMITER $$
CREATE PROCEDURE InsertSystemRoute(...)
BEGIN
-- ... 存储过程代码 ...
END$$
DELIMITER ;
-- ===================================================================
-- 在这里添加需要插入的路由
-- ===================================================================
CALL InsertSystemRoute('备注', '/route/path', '标题备注', 'ADMIN');
CALL InsertSystemRoute('备注2', '/route/path2', '标题备注', 'USER');
```
**文件命名规范:**
- 菜单:`insert_system_menu_procedure_{序号}.sql`
- 路由:`insert_system_route_procedure_{序号}.sql`
**参考示例:**
- 查看 `update_service_release/pending release 1.5.1.18/insert_system_menu_procedure_03.sql` 作为参考
**参数说明:**
**InsertSystemMenu 参数:**
- `p_remark`: 菜单备注(varchar(50))
- `p_menu_name`: 菜单名称,唯一标识(varchar(255))
- `p_title_remark`: 标题备注(varchar(50))
- `p_menu_type`: 菜单类型,'ADMIN' 或 'USER'(char(8))
- `p_description_i18n_id`: 描述国际化ID,可选(char(32)),默认为NULL
- `p_active_flag`: 激活标志,可选(smallint),默认为1
**InsertSystemRoute 参数:**
- `p_remark`: 备注
- `p_route`: 路由地址
- `p_title_remark`: 标题备注
- `p_route_type`: 路由类型('ADMIN' 或 'USER')
**功能:**
- 自动生成ID(菜单从1开始,路由从7000开始)
- 自动为相应角色模板创建权限记录
- 自动去重检查
### 1.2 创建新表
当需要创建新表时,参照 `create_table_template.sql` 中的格式:
- 使用 `CREATE TABLE IF NOT EXISTS`
- 指定正确的 schema(如 `g3fo_trade`, `g3fo_base` 等)
- 包含必要的字段、索引、注释
- 使用 `ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`
### 1.3 表结构变更
当需要修改表结构时,参照 `table_change_template.sql` 中的方法:
- 使用存储过程检查列是否存在
- 使用 `IF EXISTS` 进行幂等性检查
- 执行后删除存储过程
### 1.4 订单表字段同步规则
**重要:当 `m_order` 表需要增加字段时,以下三个表必须同时增加相同的字段:**
1. `m_order_actions` - 订单操作表(g3fo_trade schema)
2. `h_order` - 订单历史表(g3fo_trade schema)
3. `h_order_actions` - 订单操作历史表(g3fo_trade schema)
**规则说明:**
- 字段名称必须完全一致
- 字段类型必须完全一致
- 字段约束(NULL/NOT NULL、DEFAULT 等)必须完全一致
- 字段注释必须完全一致
- 字段位置(AFTER 子句)应保持一致
**SQL 生成要求:**
- 使用存储过程进行幂等性检查(参照 `table_change_template.sql`)
- 为每个表分别检查字段是否存在,不存在则添加
- 确保所有四个表的字段变更在同一个 SQL 文件中完成
- 使用相同的存储过程模式,为每个表创建独立的检查逻辑
**SQL 模板示例:**
```sql
USE g3fo_trade;
DROP PROCEDURE IF EXISTS AddOrderField;
DELIMITER $$
CREATE PROCEDURE AddOrderField()
BEGIN
-- 为 m_order 表添加字段
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_order'
AND column_name = 'new_field'
) THEN
ALTER TABLE `g3fo_trade`.`m_order`
ADD COLUMN `new_field` VARCHAR(100) NULL DEFAULT NULL COMMENT '新字段'
AFTER `existing_field`;
END IF;
-- 为 m_order_actions 表添加相同字段
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_order_actions'
AND column_name = 'new_field'
) THEN
ALTER TABLE `g3fo_trade`.`m_order_actions`
ADD COLUMN `new_field` VARCHAR(100) NULL DEFAULT NULL COMMENT '新字段'
AFTER `existing_field`;
END IF;
-- 为 h_order 表添加相同字段
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_order'
AND column_name = 'new_field'
) THEN
ALTER TABLE `g3fo_trade`.`h_order`
ADD COLUMN `new_field` VARCHAR(100) NULL DEFAULT NULL COMMENT '新字段'
AFTER `existing_field`;
END IF;
-- 为 h_order_actions 表添加相同字段
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_order_actions'
AND column_name = 'new_field'
) THEN
ALTER TABLE `g3fo_trade`.`h_order_actions`
ADD COLUMN `new_field` VARCHAR(100) NULL DEFAULT NULL COMMENT '新字段'
AFTER `existing_field`;
END IF;
END$$
DELIMITER ;
CALL AddOrderField();
DROP PROCEDURE IF EXISTS AddOrderField;
```
**注意事项:**
- 所有四个表的字段定义必须完全一致
- 必须使用幂等性检查,确保 SQL 可以重复执行
- 字段位置(AFTER 子句)应保持一致,便于维护
## 二、需要同时更新 m_system_i18n 的表
以下表在更新数据时必须同时更新 `m_system_i18n` 表:
| 表名 | i18n_id 格式 | 填充值 | 说明 |
|------|-------------|--------|------|
| `m_system_code` | `CODE-{id}` | 4位数字ID(如 `CODE-0404`) | 系统编码表 |
| `m_system_error_message` | `ERR-{id}` | 错误码ID | 系统错误消息表 |
| `m_market` | `MKT-{id}` | 4位数字ID | 市场表 |
| `m_currency` | `CURR-{code}` | 货币代码 | 货币表 |
| `m_channel` | `CH-{code}` | 渠道代码 | 渠道表 |
| `m_exchange` | `EXCH-{code}` | 交易所代码 | 交易所表 |
| `m_country` | `CNTY-{code}` | 国家代码 | 国家表 |
| `m_exchange_charge` | `EX_CHARGE-{id}` | 费用ID | 交易所费用表 |
| `m_company_charge` | `COM_CHARGE-{id}` | 费用ID | 公司费用表 |
**重要:** 所有上述表的插入和更新操作都必须同时更新 `m_system_i18n` 表,以提供多语言支持。
## 三、自动化数据插入流程
### 3.1 流程概述
1. **用户输入数据** → 2. **生成SQL语句** → 3. **用户确认** → 4. **执行SQL** → 5. **确认执行结果** → 6. **询问是否提交到Git** → 7. **Git操作**
### 3.2 以 m_system_code 为例的详细流程
#### 步骤 1: 请求用户输入
当用户需要更新或增加 `m_system_code` 的数据时,Cursor 应请求以下信息:
```
请提供以下数据:
- Code_type: [编码类型]
- Code_value: [编码值]
- Remark: [备注(用于生成多语言描述)]
- Sort: [排序号]
```
#### 步骤 2: 自动生成SQL
Cursor 自动执行以下操作:
1. **获取当前最大ID**
```sql
SELECT COALESCE(MAX(id), 0) + 1 FROM g3fo_base.m_system_code;
```
2. **生成 description_i18n_id**
- 格式:`CODE-{4位数字ID}`
- 例如:ID=404 → `CODE-0404`
3. **根据 remark 生成多语言描述**
- 如果 remark 包含中英文,自动提取
- 如果没有,使用 remark 作为英文描述
- 简体中文(sc_description):从 remark 提取或使用中文部分
- 繁体中文(tc_description):转换简体为繁体
- 越南语(vn_description):可选,如果用户提供则使用
- 法语(fr_description):可选
4. **生成 SQL 语句**
```sql
-- 插入 m_system_code
REPLACE INTO `g3fo_base`.`m_system_code`
(`id`, `code_type`, `code_value`, `description_i18n_id`, `remark`, `sort`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES
({new_id}, '{code_type}', '{code_value}', 'CODE-{formatted_id}', '{remark}', {sort}, 'sys', NOW(), 'sys', NOW());
-- 插入 m_system_i18n
REPLACE INTO `g3fo_base`.`m_system_i18n`
(`id`, `en_description`, `sc_description`, `tc_description`, `vn_description`, `fr_description`, `remark`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES
('CODE-{formatted_id}', '{en_description}', '{sc_description}', '{tc_description}', '{vn_description}', '{fr_description}', NULL, 'sys', NOW(), 'sys', NOW());
```
#### 步骤 3: 用户确认
向用户展示生成的 SQL 语句,询问:
```
已生成以下 SQL 语句,请确认数据是否正确:
[显示SQL语句]
数据是否有问题?(yes/no)
```
#### 步骤 4: 执行SQL
如果用户确认无误,使用 MySQL MCP 执行 SQL 语句:
1. 连接到数据库
2. 执行 SQL 语句
3. 验证执行结果
4. 如果成功,继续下一步;如果失败,报告错误并停止
#### 步骤 5: 询问是否提交到Git
执行成功后,询问用户:
```
SQL 执行成功!
是否需要将 SQL 提交到待执行文件夹中?(yes/no)
```
#### 步骤 6: Git 操作
如果用户确认提交,**必须按照以下顺序执行**,确保远程仓库和本地数据一致:
1. **切换到 g3fo-db 目录并拉取最新代码**(必须先执行,确保获取最新文件列表)
```bash
cd g3fo-db
git pull origin main # 或相应的分支名
```
- **重要**:这一步必须在确定文件夹和生成文件名之前执行
- 确保获取远程仓库的最新文件列表和更改
- 如果 pull 失败(如有冲突),报告错误并停止流程
2. **确定目标文件夹**(基于最新拉取的代码)
- 查找 `update_service_release` 下最新的 "pending release {version}" 文件夹
- **如果不存在,需要创建新的文件夹**:
- 查看 `update_service_release` 下所有版本号文件夹(如 `1.5.1.0`, `1.5.1.1`, `1.5.1.17` 等)
- 找到最大的版本号,新版本号 = 最大版本号 + 0.0.0.1(最后一位递增)
- 例如:如果最大版本号是 `1.5.1.17`,新版本号是 `1.5.1.18`
- 创建新文件夹:`pending release {新版本号}`
- **自动创建 `set_version_01.sql` 文件**(必须在新文件夹中创建):
- 文件内容格式:
```sql
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '1.5.1.0 M{版本号最后两位数字}',
`update_on` = NOW()
WHERE
`param_name` = 'base.systemVersion';
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '0',
`update_on` = NOW()
WHERE
`param_name` = 'base.patchNo';
```
- **版本号与 param_value 的对应关系**:
- 版本号 `1.5.1.17` → `param_value` = `'1.5.1.0 M17'`
- 版本号 `1.5.1.18` → `param_value` = `'1.5.1.0 M18'`
- 版本号 `1.5.1.19` → `param_value` = `'1.5.1.0 M19'`
- 版本号 `1.5.1.10` → `param_value` = `'1.5.1.0 M10'`
- **规律**:提取版本号的最后一部分数字(版本号格式为 X.Y.Z.N,提取 N),格式为 `'1.5.1.0 M{N}'`
- **示例**:
- `1.5.1.17` → 提取 `17` → `'1.5.1.0 M17'`
- `1.5.1.18` → 提取 `18` → `'1.5.1.0 M18'`
- `1.5.1.10` → 提取 `10` → `'1.5.1.0 M10'`
- `1.5.1.9` → 提取 `9` → `'1.5.1.0 M9'`(不补零,保持原数字)
- **注意**:此时文件夹列表是最新的,避免文件名冲突
3. **生成文件名**(基于最新的文件列表)
- 格式:`{功能描述英文}_{序号}.sql`
- 序号规则:
- **必须在 git pull 之后执行**,查看目标文件夹中已有的 SQL 文件(基于最新拉取的代码)
- **跨所有文件统一计算序号**,不区分文件名前缀
- **提取序号方法**:
1. 遍历文件夹中所有 `.sql` 文件
2. 从每个文件名中提取下划线 `_` 后面的两位数字(格式:`_XX.sql`)
3. 例如:`set_version_01.sql` → 提取 `01`,`add_system_code_02.sql` → 提取 `02`
4. 找到所有序号中的**最大值**
5. 新序号 = 最大序号 + 1
- 使用两位数字格式(01, 02, ..., 99)
- **示例**:
- 如果文件夹中有:`set_version_01.sql` 和 `add_system_code_02.sql`
- 提取的序号:`01`, `02`
- 最大序号:`02`
- 新文件序号:`03`
- 新文件名:`add_new_feature_03.sql`
- **重要**:确保序号不重复,必须基于最新拉取的代码生成
4. **检测并修复重复序号**(在保存文件之前)
- 扫描目标文件夹中所有 `.sql` 文件
- 检测是否有重复序号
- 如果发现重复,按照"5.4 重复序号检测和自动修复"规则处理
- 确保所有文件序号唯一且连续
- 如果进行了修复,生成修复报告并显示给用户
5. **保存 SQL 文件**
- 将 SQL 语句保存到目标文件夹
- 文件名使用生成的名称
6. **Git 提交和推送**
```bash
git add .
git commit -m "feat: add system code {code_type} - {code_value}"
git push origin main # 或相应的分支名
```
**如果 push 失败**(如远程有新的提交):
- 再次执行 `git pull origin main`(可能需要处理合并)
- 解决冲突后重新 push
#### 步骤 7: 完成提示
```
操作完成!
已执行的操作:
✓ SQL 语句已执行
✓ SQL 文件已保存到: update_service_release/pending release {version}/{filename}
✓ 已推送到 Git 仓库
```
## 四、其他表的处理规则
### 4.1 m_system_error_message
**输入数据:**
- Error_code: 错误码(数字)
- Message_i18n_id: 自动生成 `ERR-{error_code}`
- Remark: 英文描述
**i18n_id 生成:** `ERR-{error_code}`
**SQL 模板:**
```sql
REPLACE INTO `g3fo_base`.`m_system_error_message`
(`id`, `error_code`, `message_i18n_id`, `remark`)
VALUES
('{error_code}', 'SFO-{error_code}', 'ERR-{error_code}', '{remark}');
REPLACE INTO `g3fo_base`.`m_system_i18n`
(`id`, `en_description`, `sc_description`, `tc_description`, `vn_description`, `fr_description`, `remark`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES
('ERR-{error_code}', '{en_description}', '{sc_description}', '{tc_description}', '{vn_description}', '{fr_description}', NULL, 'sys', NOW(), 'sys', NOW());
```
### 4.2 m_market
**输入数据:**
- Market_code: 市场代码
- Market_name: 市场名称(用于生成i18n)
- 其他必要字段
**i18n_id 生成:** `MKT-{4位数字ID}`(需要先获取最大ID)
### 4.3 m_currency, m_channel, m_exchange, m_country
**输入数据:**
- Code: 代码(用于生成i18n_id)
- Name: 名称(用于生成i18n)
- 其他必要字段
**i18n_id 生成:**
- Currency: `CURR-{currency_code}`
- Channel: `CH-{channel_code}`
- Exchange: `EXCH-{exchange_code}`
- Country: `CNTY-{country_code}`
### 4.4 m_exchange_charge, m_company_charge
**输入数据:**
- 相关字段
- 描述信息(用于生成i18n)
**i18n_id 生成:**
- Exchange Charge: `EX_CHARGE-{id}`
- Company Charge: `COM_CHARGE-{id}`
## 五、文件命名规范
### 5.1 命名格式
```
{功能描述英文}_{序号}.sql
```
### 5.2 功能描述示例
- `add_system_code` - 添加系统代码
- `update_system_code` - 更新系统代码
- `add_system_error_message` - 添加错误消息
- `insert_system_route` - 插入系统路由
- `create_table_{table_name}` - 创建表
- `update_table_{table_name}_column` - 更新表列
- `add_{table_name}_data` - 添加表数据
### 5.3 序号规则
**重要:跨所有文件统一计算序号,不区分文件名前缀**
1. **查看目标文件夹中所有 `.sql` 文件**(基于最新拉取的代码)
2. **提取序号方法**:
- 遍历所有 `.sql` 文件
- 从每个文件名中提取下划线 `_` 后面的两位数字(格式:`_XX.sql`)
- 例如:
- `set_version_01.sql` → 提取 `01`
- `add_system_code_02.sql` → 提取 `02`
- `update_table_05.sql` → 提取 `05`
3. **找到所有序号中的最大值**
4. **新文件的序号 = 最大序号 + 1**
5. **使用两位数字格式(01-99)**
**示例:**
- 如果文件夹中有:`set_version_01.sql`, `add_system_code_02.sql`, `update_table_05.sql`
- 提取的序号:`01`, `02`, `05`
- 最大序号:`05`
- 新文件序号:`06`
- 新文件名:`add_new_feature_06.sql`(不限制文件名前缀)
**关键点:**
- 序号是跨所有文件统一计算的,不区分文件名前缀
- 即使已有 `xxxxxx_01.sql`,如果最大序号是 `01`,新文件应该是 `xxxxxx_02.sql`
- 如果文件夹中只有 `set_version_01.sql`,新文件应该是 `xxxxxx_02.sql`(不是 `01`)
### 5.4 重复序号检测和自动修复
**重要:在生成新文件或提交到 Git 之前,必须检测并修复重复序号**
#### 检测规则
1. **扫描目标文件夹**:检查 `update_service_release/pending release {version}/` 文件夹中所有 `.sql` 文件
2. **提取序号**:从每个文件名中提取下划线 `_` 后面的两位数字
3. **检测重复**:如果发现多个文件使用相同的序号,触发修复流程
#### 修复规则
当发现重复序号时(例如:`xxxxxx_03.sql` 和 `aaaaaaa_03.sql`),按以下步骤处理:
1. **分析文件依赖关系**:
- 比对两个文件的 SQL 内容
- 检查是否存在依赖关系:
- 文件 A 中引用了文件 B 创建的表、字段、数据等
- 文件 A 中使用了文件 B 中定义的存储过程、函数等
- 文件 A 中更新了文件 B 中插入的数据
- **依赖关系判断方法**:
- 检查 SQL 中的表名、字段名、数据值是否在另一个文件中出现
- 检查是否有 CREATE/DROP 操作在另一个文件中有对应的引用
- 检查是否有 INSERT/UPDATE 操作在另一个文件中有对应的查询
- 检查存储过程、函数的定义和调用关系
2. **确定文件顺序**:
- **如果有依赖关系**:
- 被依赖的文件(被引用)排在前面,保持原序号
- 依赖其他文件的排在后面,序号改为下一个可用序号
- **如果没有依赖关系**:
- 按照文件的创建时间(文件系统时间)确定先后顺序
- 创建时间较早的文件保持原序号
- 创建时间较晚的文件序号改为下一个可用序号
3. **自动顺延后续文件**:
- 找到下一个可用的序号(最大序号 + 1)
- 将重复序号中需要调整的文件重命名为新序号
- **检查后续文件是否需要顺延**:
- 如果新序号与后续文件序号冲突,自动顺延后续文件
- 例如:如果 `cccccc_04.sql` 和 `bbbbbbb_05.sql` 存在,且修复后新序号是 `04`
- 则 `cccccc_04.sql` → `cccccc_05.sql`,`bbbbbbb_05.sql` → `bbbbbbb_06.sql`
- 递归处理,直到没有冲突
4. **执行修复**:
- 使用 `git mv` 重命名文件(保持 Git 历史)
- 更新 Git 索引
- 生成修复报告,显示所有重命名的文件
#### 修复示例
**场景 1:有依赖关系**
- 文件:`create_table_03.sql`(创建表 `m_new_table`),`insert_data_03.sql`(向 `m_new_table` 插入数据)
- 检测:`insert_data_03.sql` 依赖 `create_table_03.sql`(引用了 `m_new_table`)
- 修复:
- `create_table_03.sql` 保持 `03`
- `insert_data_03.sql` → `insert_data_04.sql`
**场景 2:无依赖关系,按创建时间**
- 文件:`add_system_code_03.sql`(创建时间:2024-01-01),`update_setting_03.sql`(创建时间:2024-01-02)
- 检测:无依赖关系
- 修复:
- `add_system_code_03.sql` 保持 `03`(较早)
- `update_setting_03.sql` → `update_setting_04.sql`(较晚)
**场景 3:需要顺延后续文件**
- 文件:`file_a_03.sql`, `file_b_03.sql`, `file_c_04.sql`, `file_d_05.sql`
- 检测:`file_a_03.sql` 和 `file_b_03.sql` 重复,无依赖关系,`file_a_03.sql` 较早
- 修复:
- `file_a_03.sql` 保持 `03`
- `file_b_03.sql` → `file_b_04.sql`
- `file_c_04.sql` → `file_c_05.sql`(顺延,因为 `04` 已被占用)
- `file_d_05.sql` → `file_d_06.sql`(顺延,因为 `05` 已被占用)
**场景 4:多个重复序号**
- 文件:`file_a_03.sql`, `file_b_03.sql`, `file_c_04.sql`, `file_d_04.sql`, `file_e_05.sql`
- 检测:`03` 重复,`04` 也重复
- 修复:
- 先处理 `03` 的重复:`file_a_03.sql` 保持 `03`,`file_b_03.sql` → `file_b_04.sql`
- 再处理 `04` 的重复:`file_c_04.sql` 保持 `04`,`file_d_04.sql` → `file_d_05.sql`
- 顺延:`file_e_05.sql` → `file_e_06.sql`
#### 执行时机
- **在生成新文件之前**:先检测并修复现有文件的重复序号
- **在提交到 Git 之前**:再次检测并修复,确保没有重复序号
- **可以手动触发**:用户要求检测和修复时
#### 修复报告格式
修复完成后,生成报告:
```
检测到重复序号,已自动修复:
修复的文件:
- file_b_03.sql → file_b_04.sql(原因:与 file_a_03.sql 重复,无依赖关系,按创建时间调整)
- file_c_04.sql → file_c_05.sql(原因:序号冲突,自动顺延)
- file_d_05.sql → file_d_06.sql(原因:序号冲突,自动顺延)
所有文件序号已修复,无重复。
```
## 六、SQL 语句规范
### 6.1 使用 REPLACE INTO
对于数据插入和更新,使用 `REPLACE INTO` 而不是 `INSERT INTO`,以确保幂等性:
```sql
REPLACE INTO `schema`.`table_name`
(`column1`, `column2`, ...)
VALUES
('value1', 'value2', ...);
```
### 6.2 时间戳字段
- `create_on`: `NOW()` 或 `CURRENT_TIMESTAMP`
- `update_on`: `NOW()` 或 `CURRENT_TIMESTAMP`
- `create_by`: `'sys'`(系统操作)或实际用户名
- `update_by`: `'sys'`(系统操作)或实际用户名
### 6.3 注释
在 SQL 文件开头添加注释说明:
```sql
-- ===================================================================
-- 功能描述:添加系统代码
-- 表名:m_system_code, m_system_i18n
-- 创建时间:{date}
-- ===================================================================
```
## 七、Git 操作规范
### 7.1 操作顺序(重要)
**必须严格按照以下顺序执行 Git 操作,确保远程仓库和本地数据一致:**
1. **先执行 `git pull`** - 获取最新代码和文件列表
2. **然后确定目标文件夹** - 基于最新拉取的代码
3. **生成文件名** - 基于最新的文件列表,避免序号冲突
4. **保存文件** - 创建 SQL 文件
5. **最后执行 `git add`, `commit`, `push`** - 提交更改
**为什么必须先 pull?**
- 确保获取远程仓库的最新文件列表
- 避免文件名序号冲突(其他人可能已经添加了新文件)
- 避免覆盖其他人的更改
- 确保本地和远程仓库的一致性
### 7.2 Commit 消息格式
```
feat: {简短描述}
详细说明(可选)
```
**示例:**
- `feat: add system code OrderType - 015`
- `feat: add system error message SFO-17100`
- `feat: insert system route /trade/order/retryOrder`
### 7.3 分支管理
- 默认推送到 `main` 分支
- 如果项目使用其他分支策略,遵循项目规范
### 7.4 冲突处理
如果 `git pull` 时出现冲突:
1. 报告冲突文件
2. 询问用户是否手动解决
3. 或提供解决建议
4. **不要继续执行后续步骤**,直到冲突解决
如果 `git push` 时失败(远程有新的提交):
1. 再次执行 `git pull origin main`(可能需要处理合并)
2. 解决冲突后重新 push
## 八、错误处理
### 8.1 SQL 执行失败
- 显示错误信息
- 不执行 Git 操作
- 询问用户是否重试
### 8.2 Git 操作失败
- 显示错误信息
- SQL 文件已保存到本地
- 提供手动 Git 操作建议
### 8.3 数据验证失败
- 在生成 SQL 前验证数据格式
- 如果验证失败,提示用户修正
## 九、重要提醒
### 9.1 必须同时更新的表
1. **i18n 表更新**:所有需要多语言支持的表操作都必须同时更新 `m_system_i18n` 表
2. **订单表字段同步**:当 `m_order` 表增加字段时,必须同时在以下三个表中增加相同字段:
- `m_order_actions` - 订单操作表
- `h_order` - 订单历史表
- `h_order_actions` - 订单操作历史表
### 9.2 菜单和路径权限处理规则
**重要:增加菜单和路径权限必须使用存储过程文件**
1. **执行 SQL 阶段**:
- 由于 MySQL MCP 不支持 `DELIMITER`,可以使用直接的 `INSERT INTO` 或 `REPLACE INTO` 语句执行
- 确保数据与存储过程生成的数据完全一致
2. **提交到 Git 阶段**:
- **必须使用存储过程文件生成的完整 SQL**
- 从 `common_sql` 文件夹复制完整的存储过程定义
- 在文件末尾添加 `CALL` 语句
- 参考 `update_service_release/pending release 1.5.1.18` 中的文件格式
### 9.3 其他重要规则
1. 所有 SQL 文件必须保存到正确的版本文件夹中
2. **文件序号不能重复,必须递增。在生成新文件和提交到 Git 之前,必须检测并修复重复序号**
3. 使用 REPLACE INTO 确保 SQL 可以重复执行
4. 执行 SQL 前必须获得用户确认
5. 表结构变更必须使用存储过程进行幂等性检查
## 十、持续改进
本流程是一个持续更新和改进的流程。在使用过程中,如果发现以下情况,应该更新本文档:
1. 发现新的需要 i18n 的表
2. 发现新的需要同步字段的表(如订单表字段同步规则)
3. 发现新的命名规范或格式要求
4. 发现流程中的问题或改进点
5. 添加新的模板或工具
## 十一、使用示例
### 示例 1: 添加系统代码
**用户输入:**
```
我需要添加一个新的系统代码:
- Code_type: OrderType
- Code_value: 016
- Remark: Market Order (HK)
- Sort: 17
```
**Cursor 处理:**
1. 查询最大ID:假设当前最大ID是 404
2. 生成新ID:405
3. 生成 i18n_id:CODE-0405
4. 生成多语言描述:
- en: Market Order (HK)
- sc: 市价单(香港)
- tc: 市價單(香港)
- vn: (可选)
5. 生成 SQL 并展示
6. 用户确认后执行
7. 执行成功后询问是否提交到 Git
8. 如果确认,保存文件并推送到 Git
### 示例 2: 插入系统路由
**用户输入:**
```
我需要添加一个新的系统路由:
- Route: /trade/order/cancel
- Route_type: USER
- Remark: 取消订单
- Title_remark: 订单
```
**Cursor 处理:**
1. 使用 `insert_system_route_procedure.sql` 模板
2. 生成 SQL:
```sql
CALL InsertSystemRoute('取消订单', '/trade/order/cancel', '订单', 'USER');
```
3. 执行并提交到 Git
## 附录
### A. 常用 SQL 查询
**获取最大ID:**
```sql
SELECT COALESCE(MAX(id), 0) + 1 FROM g3fo_base.m_system_code;
```
**检查记录是否存在:**
```sql
SELECT COUNT(*) FROM g3fo_base.m_system_code
WHERE code_type = '{code_type}' AND code_value = '{code_value}';
```
**获取当前版本号:**
```sql
SELECT param_value FROM g3fo_base.m_system_setting
WHERE param_name = 'base.systemVersion';
```
### B. 多语言描述生成规则
1. **如果 remark 包含中英文:**
- 提取英文部分作为 `en_description`
- 提取中文部分作为 `sc_description`
- 转换简体为繁体作为 `tc_description`
2. **如果 remark 只有中文:**
- 使用 remark 作为 `sc_description` 和 `tc_description`
- 询问用户英文描述,或使用拼音/音译
3. **如果 remark 只有英文:**
- 使用 remark 作为 `en_description`
- 询问用户中文描述
### C. 联系和支持
如有问题或建议,请更新本文档或联系项目维护者。
@@ -0,0 +1,101 @@
# SQL Site Naming Convention
本文档说明了项目中使用的 SQL 站点命名规则及其对应关系。
## 站点命名对照表
| 目录名称 | 对应站点 | IP地址 | 描述 |
|---------|---------------|--------|------|
| afe_ap | Alpha Site | | |
| dls_ap | DLS | | |
| hing_wai_ap | HingWai | | |
| vn-demo | VN Demo | | |
| vn-demo-local | VN Demo Local | | |
| 226 | UAT | | |
## 目录结构与执行机制
### update_service_release 目录结构
项目中的 SQL 文件按照以下结构组织:
```
update_service_release/
├── 版本号/ # 如 1.5.1.20
│ ├── sitename/ # 如 afe_ap, dls_ap 等
│ │ ├── patch/ # 补丁目录
│ │ │ └── 数字版本/ # 如 1, 2 等
│ │ │ └── *.sql # 补丁 SQL 文件
│ │ └── *.sql # 该站点特定的 SQL 文件
│ └── *.sql # 通用 SQL 文件
└── pending release x.x.x.x/ # 当前开发中的版本
```
### SQL 执行机制
1. **版本发布目录**:
- 每个版本号目录下包含适用于不同站点的 SQL 文件
- 站点特定的 SQL 文件放在对应的 `sitename` 子目录中
- 补丁文件放在对应站点的 `patch` 子目录中,按数字版本号分组
- 通用 SQL 文件直接放在版本号目录下
2. **当前开发版本**:
- `update_service_release/pending release x.x.x.x` 是当前正在开发的版本目录
- 每个版本下必须包含一个修改版本号的 SQL 文件:`set_version_01.sql`
- 该文件负责更新系统版本信息到 `m_system_setting` 表
3. **Jenkins 自动化执行**:
- 通过执行 `1-g3fo-db`/`g3fo-db-patch` 任务运行 SQL
- 大版本升级执行`1-g3fo-db`,只能执行一次
- 补丁执行`g3fo-db-patch`,可重复执行
- 系统会根据指定的站点和版本号执行对应目录下的 SQL 文件
- 默认执行版本号最大的 patch(可重复执行,保证幂等性)
### 版本号更新文件示例
每个版本必须包含 `set_version_01.sql` 文件,其内容如下(控实际情况修改版本号,以下是1.5.1.20版本示例):
```sql
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '1.5.1.0 M20',
`update_on` = NOW()
WHERE
`param_name` = 'base.systemVersion';
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '0',
`update_on` = NOW()
WHERE
`param_name` = 'base.patchNo';
```
## 命名一致性要求
为了确保自动化部署和执行流程的正常运行,`sitename` 目录命名必须与以下配置保持严格一致:
1. **Jenkins 配置**:
- Jenkins -> 系统管理 -> Publish over SSH -> SSH Server Name 中配置的服务名
- 例如:如果 Jenkins 中配置的 SSH Server Name 为 `afe_ap`,则目录名必须也为 `afe_ap`
2. **执行服务器配置**:
- 与执行 SQL 的服务器(Build 机或 support 机)上的 `/data/g3dbExecution/db_config.json` 文件中的 key 保持一致
- 该 JSON 文件中的 key 值必须与目录名称完全匹配
这种一致性确保了:
- Jenkins 能够正确地将 SQL 文件传输到目标服务器
- SQL 脚本能够在正确的环境中执行
- 部署流程能够自动化进行而不会出现配置错误
## 添加新环境
当需要添加新的部署环境时,请遵循以下命名规则:
- 生产环境:使用客户名称的缩写加 `_ap` 后缀
- 测试环境:使用环境用途加版本号或标识符的形式
## 注意事项
- 所有命名应保持简洁明了
- 同一类环境应保持命名风格一致
- 添加新环境后应及时更新此文档
- 修改现有环境名称前需确认关联的所有配置均已同步更新
@@ -0,0 +1,49 @@
CREATE TABLE IF NOT EXISTS `g3fo_trade`.`m_trading_planned_order` (
`creator` CHAR(36) NOT NULL,
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
`planned_order_id` VARCHAR(40) NOT NULL,
`strategy_id` CHAR(36) NOT NULL,
`strategy_name` CHAR(64) NOT NULL,
`account_type` VARCHAR(3) NOT NULL,
`account_id` VARCHAR(20) NOT NULL,
`trading_day` DATE NOT NULL,
`order_dt` DATETIME(6) NULL DEFAULT NULL,
`exchange` VARCHAR(8) NOT NULL,
`instrument` VARCHAR(64) NOT NULL,
`name` VARCHAR(64) NOT NULL,
`direction` VARCHAR(1) NOT NULL,
`offset_flag` VARCHAR(4) NOT NULL,
`original_order_qty` INT NOT NULL DEFAULT 0,
`order_qty` INT NOT NULL DEFAULT 0,
`order_price` DOUBLE NOT NULL DEFAULT 0,
`order_type` VARCHAR(1) NOT NULL,
`order_status` SMALLINT NOT NULL,
`status_msg` VARCHAR(64) NOT NULL,
`order_params` JSON NULL DEFAULT NULL,
`order_placed_dt` DATETIME(6) NULL DEFAULT NULL,
`order_key` VARCHAR(32) NULL DEFAULT '',
`entrust_no` VARCHAR(32) NULL DEFAULT '',
`algo_order_id` BIGINT NULL DEFAULT 0,
`stop_profit_price` DOUBLE NULL DEFAULT 0,
`stop_loss_price` DOUBLE NULL DEFAULT 0,
`system_order_count` BIGINT NULL,
`system_account_id` BIGINT NULL,
`modified_qty` INT NULL DEFAULT 0,
`modified_price` DOUBLE NULL DEFAULT 0,
`system_user_id` BIGINT NULL,
`execute_status` CHAR(4) NULL DEFAULT '0',
`eng_name` CHAR(128) NULL,
`local_name` CHAR(128) NULL,
`sc_name` CHAR(128) NULL,
`create_on` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
`create_by` VARCHAR(32) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_0900_ai_ci' NULL DEFAULT NULL,
`update_on` TIMESTAMP NULL DEFAULT NULL,
`update_by` VARCHAR(32) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_0900_ai_ci' NULL DEFAULT NULL,
PRIMARY KEY (`planned_order_id`),
INDEX `idx_strategy_id` (`strategy_id`),
INDEX `idx_user_id` (`system_user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='quant strategy order plan';
@@ -0,0 +1,265 @@
-- ------------------------------------------------------------
-- Hing Wai AP 清理与初始化脚本
-- 将原先分散的脚本合并,按模块分组执行
-- ------------------------------------------------------------
-- ===============================
-- g3fo_trade 历史与当日数据清理
-- ===============================
TRUNCATE TABLE `g3fo_trade`.`h_order`;
TRUNCATE TABLE `g3fo_trade`.`h_order_actions`;
TRUNCATE TABLE `g3fo_trade`.`h_strategy_daily_profit`;
TRUNCATE TABLE `g3fo_trade`.`h_trade`;
TRUNCATE TABLE `g3fo_trade`.`m_order`;
TRUNCATE TABLE `g3fo_trade`.`m_order_actions`;
TRUNCATE TABLE `g3fo_trade`.`m_order_approve_detail`;
TRUNCATE TABLE `g3fo_trade`.`m_strategy_daily_profit`;
TRUNCATE TABLE `g3fo_trade`.`m_trade`;
TRUNCATE TABLE `g3fo_trade`.`m_trading_planned_order`;
TRUNCATE TABLE `g3fo_trade`.`m_user_account_chunk`;
-- TRUNCATE TABLE `g3fo_trade`.`m_user_account_map`;
TRUNCATE TABLE `g3fo_trade`.`m_user_api_binding`;
TRUNCATE TABLE `g3fo_trade`.`m_user_approve_order_record`;
TRUNCATE TABLE `g3fo_trade`.`m_user_credit_usage_sum`;
-- ===============================
-- g3fo_dx 相关表清理
-- ===============================
TRUNCATE TABLE `g3fo_dx`.`m_async_task`;
TRUNCATE TABLE `g3fo_dx`.`m_async_task_history`;
TRUNCATE TABLE `g3fo_dx`.`m_dx_message_in_history`;
TRUNCATE TABLE `g3fo_dx`.`m_dx_message_out_history`;
TRUNCATE TABLE `g3fo_dx`.`m_dx_session`;
TRUNCATE TABLE `g3fo_dx`.`m_import_history`;
-- ===============================
-- 日志表清理
-- ===============================
TRUNCATE TABLE `g3fo_admin`.`m_report_export_record`;
TRUNCATE TABLE `g3fo_admin`.`m_table_data_change_log`;
TRUNCATE TABLE `g3fo_base`.`m_fix_message_log`;
TRUNCATE TABLE `nacos`.`his_config_info`;
-- ===============================
-- g3fo_user 账户、客户与用户相关表清理
-- ===============================
TRUNCATE TABLE `g3fo_user`.`m_account`;
TRUNCATE TABLE `g3fo_user`.`m_account_bank`;
TRUNCATE TABLE `g3fo_user`.`m_account_bcan_history`;
TRUNCATE TABLE `g3fo_user`.`m_account_black_white_list`;
TRUNCATE TABLE `g3fo_user`.`m_account_cash_hold`;
TRUNCATE TABLE `g3fo_user`.`m_account_cash_movement`;
TRUNCATE TABLE `g3fo_user`.`m_account_cash_open`;
TRUNCATE TABLE `g3fo_user`.`m_account_company_charge`;
TRUNCATE TABLE `g3fo_user`.`m_account_order_hold`;
TRUNCATE TABLE `g3fo_user`.`m_account_product_hold`;
TRUNCATE TABLE `g3fo_user`.`m_account_product_margin`;
TRUNCATE TABLE `g3fo_user`.`m_account_product_movement`;
TRUNCATE TABLE `g3fo_user`.`m_account_product_open`;
TRUNCATE TABLE `g3fo_user`.`m_account_trade_license`;
TRUNCATE TABLE `g3fo_user`.`m_alert_message`;
TRUNCATE TABLE `g3fo_user`.`m_aml`;
TRUNCATE TABLE `g3fo_user`.`m_authorized_person`;
TRUNCATE TABLE `g3fo_user`.`m_black_white_list`;
TRUNCATE TABLE `g3fo_user`.`m_broker_mapping`;
TRUNCATE TABLE `g3fo_user`.`m_client`;
TRUNCATE TABLE `g3fo_user`.`m_client_account_relations`;
TRUNCATE TABLE `g3fo_user`.`m_client_hot_list`;
TRUNCATE TABLE `g3fo_user`.`m_group`;
TRUNCATE TABLE `g3fo_user`.`m_group_item`;
TRUNCATE TABLE `g3fo_user`.`m_settled_trade`;
TRUNCATE TABLE `g3fo_user`.`m_settled_trade_charge`;
TRUNCATE TABLE `g3fo_user`.`m_settled_trade_dtl`;
TRUNCATE TABLE `g3fo_user`.`m_settled_trade_qty`;
TRUNCATE TABLE `g3fo_user`.`m_settled_trade_rebate`;
TRUNCATE TABLE `g3fo_user`.`m_user`;
TRUNCATE TABLE `g3fo_user`.`m_user_change_password`;
TRUNCATE TABLE `g3fo_user`.`m_user_client_relations`;
TRUNCATE TABLE `g3fo_user`.`m_user_login`;
TRUNCATE TABLE `g3fo_user`.`m_user_login_history`;
TRUNCATE TABLE `g3fo_user`.`m_user_role_relation_def`;
TRUNCATE TABLE `g3fo_user`.`m_user_trade_license`;
TRUNCATE TABLE `g3fo_user`.`t_user_account_ref`;
TRUNCATE TABLE `g3fo_user`.`t_user_child_user_ref`;
TRUNCATE TABLE `g3fo_user`.`t_user_client_ref`;
-- ===============================
-- g3fo_admin 管理员相关表清理
-- ===============================
TRUNCATE TABLE `g3fo_admin`.`m_admin`;
TRUNCATE TABLE `g3fo_admin`.`m_admin_login`;
TRUNCATE TABLE `g3fo_admin`.`m_admin_role_relation_def`;
-- ===============================
-- 初始化 g3fo_user 账户与客户数据
-- ===============================
REPLACE INTO `g3fo_user`.`m_account` (`id`, `account_type`, `account_code`, `account_class`, `account_status`, `local_name`, `eng_name`, `single_order_limit`, `daily_limit`, `cny_single_order_limit`, `cny_daily_limit`, `margin_pct`, `cover_pct`, `margin_limit`, `risk_agree`, `professional_investor_flag`, `aml_risk_level`, `client_risk_level`, `ae_id`, `parent_id`, `staff_account_flag`, `black_white_list_code`, `alert_pro_account`, `promotion_flag`, `hkidr_consent_flag`, `hkidr_consent_date`, `tel_no_home`, `tel_no_office`, `tel_no_mobile`, `tel_no_sms`, `fax_no_home`, `fax_no_office`, `address1_home`, `address2_home`, `address3_home`, `address4_home`, `address1_office`, `address2_office`, `address3_office`, `address4_office`, `area_code`, `birth_date`, `sex`, `occupation`, `referee`, `nationality`, `country_code`, `email`, `remark`, `buy_side_id`, `attention`, `id_card`, `virtual_asset_assessment_date`, `by_pass_check`, `create_by`, `create_on`, `update_by`, `update_on`, `member_type`, `default_ap_id`, `bank_gateway`, `bg_cia_flg`, `bg_offline_flg`, `online_cia_flg`, `online_monthly_rpt_flg`, `online_rights_sub_flg`, `online_stock_transfer_flg`, `online_trade_status`, `online_withdrawal`, `oct_flg`, `acct_grp`, `cash_limit`, `credit_limit`, `margin_call_pct`, `max_daily_transfer_limit`, `max_margin_flg`, `mdar`, `used_allocated_credit`, `used_credit`, `allocated_credit`, `bfld`, `bfld_discount`, `over_limit_proc`, `stop_buy_pct`, `stop_withdrawal_pct`, `concentration_risk`, `confidential`, `force_sell_flg`, `force_sell_note`, `force_sell_pct`, `force_sell_period`, `day_to_force_sell`, `t_plus_flg`, `t_plus_term`, `email_statement`, `close_date`, `phone_code`)
VALUES (1, 'CASH', 'afe', 'CASH', 'OPEN', 'AFE', 'afe.hk', 999999999.99, 999999999.99, 999999999.99, 999999999.99, 5.000000, 6.000000, 7.00, 'EQUY,BOND,WART', '1', NULL, NULL, NULL, '', '1', '', '', 1, 1, '2024-06-12 00:00:00', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', NULL, NULL, '', '', '', '', 'afe@afe.hk', '', '', '', '', NULL, 0, 'sys', '2024-05-15 11:32:52', 'sys', '2025-02-24 17:48:02', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_account` (`id`, `account_type`, `account_code`, `account_class`, `account_status`, `local_name`, `eng_name`, `single_order_limit`, `daily_limit`, `cny_single_order_limit`, `cny_daily_limit`, `margin_pct`, `cover_pct`, `margin_limit`, `risk_agree`, `professional_investor_flag`, `aml_risk_level`, `client_risk_level`, `ae_id`, `parent_id`, `staff_account_flag`, `black_white_list_code`, `alert_pro_account`, `promotion_flag`, `hkidr_consent_flag`, `hkidr_consent_date`, `tel_no_home`, `tel_no_office`, `tel_no_mobile`, `tel_no_sms`, `fax_no_home`, `fax_no_office`, `address1_home`, `address2_home`, `address3_home`, `address4_home`, `address1_office`, `address2_office`, `address3_office`, `address4_office`, `area_code`, `birth_date`, `sex`, `occupation`, `referee`, `nationality`, `country_code`, `email`, `remark`, `buy_side_id`, `attention`, `id_card`, `virtual_asset_assessment_date`, `by_pass_check`, `create_by`, `create_on`, `update_by`, `update_on`, `member_type`, `default_ap_id`, `bank_gateway`, `bg_cia_flg`, `bg_offline_flg`, `online_cia_flg`, `online_monthly_rpt_flg`, `online_rights_sub_flg`, `online_stock_transfer_flg`, `online_trade_status`, `online_withdrawal`, `oct_flg`, `acct_grp`, `cash_limit`, `credit_limit`, `margin_call_pct`, `max_daily_transfer_limit`, `max_margin_flg`, `mdar`, `used_allocated_credit`, `used_credit`, `allocated_credit`, `bfld`, `bfld_discount`, `over_limit_proc`, `stop_buy_pct`, `stop_withdrawal_pct`, `concentration_risk`, `confidential`, `force_sell_flg`, `force_sell_note`, `force_sell_pct`, `force_sell_period`, `day_to_force_sell`, `t_plus_flg`, `t_plus_term`, `email_statement`, `close_date`, `phone_code`)
VALUES (1943513637545185280, 'CASH', 'APPSTORE1', 'CUST', 'OPEN', 'APPSTORE1', 'APPSTORE1', 0.00, 0.00, 0.00, 0.00, 0.000000, 0.000000, 999999999999999.99, 'EQUY,BOND,TRUT', '0', NULL, NULL, 'C05', '', '0', '', '', 0, 1, '2025-04-03 00:00:00', '', '', '', '', '', '', '紅磡德豐街 18 號海濱廣場一期19樓1907B-1910A室', '', '', '', '', '', '', '', '', NULL, NULL, '', '', 'HK', '', '', '', '', '', '', NULL, 0, 'sys', '2025-07-11 11:32:15', 'DX', '2025-08-22 13:52:44', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_account` (`id`, `account_type`, `account_code`, `account_class`, `account_status`, `local_name`, `eng_name`, `single_order_limit`, `daily_limit`, `cny_single_order_limit`, `cny_daily_limit`, `margin_pct`, `cover_pct`, `margin_limit`, `risk_agree`, `professional_investor_flag`, `aml_risk_level`, `client_risk_level`, `ae_id`, `parent_id`, `staff_account_flag`, `black_white_list_code`, `alert_pro_account`, `promotion_flag`, `hkidr_consent_flag`, `hkidr_consent_date`, `tel_no_home`, `tel_no_office`, `tel_no_mobile`, `tel_no_sms`, `fax_no_home`, `fax_no_office`, `address1_home`, `address2_home`, `address3_home`, `address4_home`, `address1_office`, `address2_office`, `address3_office`, `address4_office`, `area_code`, `birth_date`, `sex`, `occupation`, `referee`, `nationality`, `country_code`, `email`, `remark`, `buy_side_id`, `attention`, `id_card`, `virtual_asset_assessment_date`, `by_pass_check`, `create_by`, `create_on`, `update_by`, `update_on`, `member_type`, `default_ap_id`, `bank_gateway`, `bg_cia_flg`, `bg_offline_flg`, `online_cia_flg`, `online_monthly_rpt_flg`, `online_rights_sub_flg`, `online_stock_transfer_flg`, `online_trade_status`, `online_withdrawal`, `oct_flg`, `acct_grp`, `cash_limit`, `credit_limit`, `margin_call_pct`, `max_daily_transfer_limit`, `max_margin_flg`, `mdar`, `used_allocated_credit`, `used_credit`, `allocated_credit`, `bfld`, `bfld_discount`, `over_limit_proc`, `stop_buy_pct`, `stop_withdrawal_pct`, `concentration_risk`, `confidential`, `force_sell_flg`, `force_sell_note`, `force_sell_pct`, `force_sell_period`, `day_to_force_sell`, `t_plus_flg`, `t_plus_term`, `email_statement`, `close_date`, `phone_code`) VALUES (1980186019865169920, 'CASH', 'HOUSE_ACCOUNT', 'CASH', 'OPEN', '', 'HOUSE_ACCOUNT', 99999999999.00, 99999999999.00, 99999999999.00, 99999999999.00, 5.000000, 6.000000, 7.00, 'WART,BOND,EQUY,TRUT', '1', NULL, NULL, NULL, '', '0', '', '', 0, 1, '2025-10-20 00:00:00', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', NULL, NULL, '', '', '', '', '', '', '', '', '', NULL, 0, 'afe', '2025-10-20 16:15:12', 'afe', '2025-10-20 16:27:38', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_account_trade_license` (`id`, `account_id`, `account_code`, `exchange_code`, `market_ids`, `account_status`, `risk_rule_group_code`, `over_limit_proc`, `clear_type`, `base_currency_code`, `clear_currency_code`, `payee`, `beneficiary`, `last_txn_date`, `last_trader_id`, `acct_terminated_date`, `single_order_limit`, `daily_limit`, `margin_pct`, `multiplier`, `recall_time`, `investor_id`, `bcan`, `bcan_validated_flag`, `ttep_flag`, `bcan_range_from`, `bcan_range_to`, `bcan_range_validated_list`, `create_by`, `create_on`, `update_by`, `update_on`, `smp_id`, `short_sell_flag`, `broker_ids`, `risk_class`, `acct_class`)
VALUES (1943513736174243840, 1943513637545185280, 'APPSTORE1', 'SEHK', '1,7,8,9', 'OPEN', 'CASH', 'OVER', 'T', 'HKD', 'HKD', '', '', NULL, '', NULL, 0.00, 0.00, 0.000000, NULL, NULL, '', 'ABL962.2266', 0, 0, '', '', '', 'sys', '2025-07-11 11:32:38', 'DX', '2025-08-22 13:47:50', '', 0, NULL, NULL, NULL);
INSERT INTO `g3fo_user`.`m_account_trade_license` (`id`, `account_id`, `account_code`, `exchange_code`, `market_ids`, `account_status`, `risk_rule_group_code`, `over_limit_proc`, `clear_type`, `base_currency_code`, `clear_currency_code`, `payee`, `beneficiary`, `last_txn_date`, `last_trader_id`, `acct_terminated_date`, `single_order_limit`, `daily_limit`, `margin_pct`, `multiplier`, `recall_time`, `investor_id`, `bcan`, `bcan_validated_flag`, `ttep_flag`, `bcan_range_from`, `bcan_range_to`, `bcan_range_validated_list`, `create_by`, `create_on`, `update_by`, `update_on`, `smp_id`, `short_sell_flag`, `broker_ids`, `risk_class`, `acct_class`) VALUES (1980186084428091392, 1980186019865169920, 'HOUSE_ACCOUNT', 'SEHK', '1,7,8,9', 'OPEN', 'CASH', 'OVER', 'T', 'HKD', 'HKD', '', '', NULL, '', NULL, 0.00, 0.00, 0.000000, NULL, NULL, '', '', 0, 0, '', '', '', 'afe', '2025-10-20 16:15:27', 'afe', '2025-10-20 21:36:47', '', 1, NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_client` (`id`, `client_code`, `local_name`, `eng_name`, `group_code`, `branch_code`, `single_order_limit`, `daily_limit`, `cny_single_order_limit`, `cny_daily_limit`, `tel_no_home`, `tel_no_office`, `tel_no_mobile`, `tel_no_sms`, `notify_lang`, `trade_notify_method`, `price_alert_notify_method`, `system_msg_notify_method`, `news_notify_method`, `fax_no_home`, `fax_no_office`, `address1_home`, `address2_home`, `address3_home`, `address4_home`, `address1_office`, `address2_office`, `address3_office`, `address4_office`, `area_code`, `birth_date`, `sex`, `occupation`, `referee`, `nationality`, `country_code`, `email`, `remark`, `buy_side_id`, `attention`, `id_card`, `owner_user_id`, `create_by`, `create_on`, `update_by`, `update_on`, `custody_id`, `bank_gateway`, `client_signature`, `omnibus_acc_flg`, `sms_flg`, `id_issue_date`, `id_issue_place`, `id_type`, `trading_code`, `trading_code_issue_date`, `residence_expiry_date`)
VALUES (1943513539612381184, 'APPSTORE1', 'APPSTORE1', 'APPSTORE1', 'COMPANY-GROUP', 'DEF', 0.00, 0.00, 0.00, 0.00, '', '', '', NULL, NULL, 'MOBI', '', '', '', '', '', '紅磡德豐街 18 號海濱廣場一期19樓1907B-1910A室', '', '', '', '', '', '', '', '', NULL, 'M', '', '', 'Hong Kong', 'HK', '', '', NULL, NULL, NULL, NULL, 'sys', '2025-07-11 11:31:51', 'sys', '2025-08-22 13:58:02', 'APPSTORE1', NULL, '', 0, NULL, NULL, 'HK', 'I', NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_client` (`id`, `client_code`, `local_name`, `eng_name`, `group_code`, `branch_code`, `single_order_limit`, `daily_limit`, `cny_single_order_limit`, `cny_daily_limit`, `tel_no_home`, `tel_no_office`, `tel_no_mobile`, `tel_no_sms`, `notify_lang`, `trade_notify_method`, `price_alert_notify_method`, `system_msg_notify_method`, `news_notify_method`, `fax_no_home`, `fax_no_office`, `address1_home`, `address2_home`, `address3_home`, `address4_home`, `address1_office`, `address2_office`, `address3_office`, `address4_office`, `area_code`, `birth_date`, `sex`, `occupation`, `referee`, `nationality`, `country_code`, `email`, `remark`, `buy_side_id`, `attention`, `id_card`, `owner_user_id`, `create_by`, `create_on`, `update_by`, `update_on`, `custody_id`, `bank_gateway`, `client_signature`, `omnibus_acc_flg`, `sms_flg`, `id_issue_date`, `id_issue_place`, `id_type`, `trading_code`, `trading_code_issue_date`, `residence_expiry_date`)
VALUES (1, 'afe', 'AFE', 'afe.hk', NULL, '001', 0.00, 0.00, 0.00, 0.00, '1111', '2222', '3333', '4444', NULL, 'EMAL', NULL, NULL, NULL, '888888888', '999999999', 'j11111111', 'j22222222', 'j333333333', 'j4444444', 'b11111111', 'b2222222', 'b333333333', 'b44444444', '11111111', NULL, NULL, '', '', '', '', 'man.zhong@afe.hk', '', '', '', '', NULL, 'admin', '2023-09-12 14:53:46', 'sys', '2025-03-19 15:51:22', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_client` (`id`, `client_code`, `local_name`, `eng_name`, `group_code`, `branch_code`, `single_order_limit`, `daily_limit`, `cny_single_order_limit`, `cny_daily_limit`, `tel_no_home`, `tel_no_office`, `tel_no_mobile`, `tel_no_sms`, `notify_lang`, `trade_notify_method`, `price_alert_notify_method`, `system_msg_notify_method`, `news_notify_method`, `fax_no_home`, `fax_no_office`, `address1_home`, `address2_home`, `address3_home`, `address4_home`, `address1_office`, `address2_office`, `address3_office`, `address4_office`, `area_code`, `birth_date`, `sex`, `occupation`, `referee`, `nationality`, `country_code`, `email`, `remark`, `buy_side_id`, `attention`, `id_card`, `owner_user_id`, `create_by`, `create_on`, `update_by`, `update_on`, `custody_id`, `bank_gateway`, `client_signature`, `omnibus_acc_flg`, `sms_flg`, `id_issue_date`, `id_issue_place`, `id_type`, `trading_code`, `trading_code_issue_date`, `residence_expiry_date`) VALUES (1980185872708014080, 'HOUSE_ACCOUNT', 'HOUSE_ACCOUNT', 'HOUSE_ACCOUNT', 'COMPANY-GROUP', 'DEFAULT', 0.00, 0.00, 0.00, 0.00, '', '', '', '', NULL, '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', NULL, 'M', '', '', '', 'AU', 'leon@e-hingwai.com', '', '', '', '', NULL, 'afe', '2025-10-20 16:14:37', 'afe', '2025-10-20 16:26:40', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_client_account_relations` (`id`, `client_id`, `client_code`, `account_id`, `account_code`, `account_type`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1, 1, 'afe', 1, 'afe', 'CASH', 'sys', '2025-02-24 17:52:23', NULL, NULL);
REPLACE INTO `g3fo_user`.`m_client_account_relations` (`id`, `client_id`, `client_code`, `account_id`, `account_code`, `account_type`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1958767774625042432, 1943513539612381184, 'APPSTORE1', 1943513637545185280, 'APPSTORE1', 'CASH', 'DX', '2025-08-22 13:46:44', 'sys', '2025-08-22 13:46:44');
REPLACE INTO `g3fo_user`.`m_client_account_relations` (`id`, `client_id`, `client_code`, `account_id`, `account_code`, `account_type`, `create_by`, `create_on`, `update_by`, `update_on`) VALUES (1980189147855458304, 1980185872708014080, 'HOUSE_ACCOUNT', 1980186019865169920, 'HOUSE_ACCOUNT', 'CASH', 'afe', '2025-10-20 16:27:38', 'afe', '2025-10-20 16:27:38');
REPLACE INTO `g3fo_user`.`m_group` (`id`, `group_code`, `group_type`, `local_name`, `eng_name`, `description`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1, 'COMPANY-GROUP', 'CG', '公司组', 'COMPANY-GROUP', NULL, 'sql', '2025-05-07 10:56:09', NULL, NULL);
REPLACE INTO `g3fo_user`.`m_group_item` (`id`, `group_type`, `group_id`, `group_code`, `child_type`, `child_id`, `child_code`, `enable_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1943513539805319168, 'CG', 1, 'COMPANY-GROUP', 'C', 1943513539612381184, 'APPSTORE1', 1, 'sys', '2025-07-11 11:31:51', 'sys', '2025-07-11 11:31:51');
INSERT INTO `g3fo_user`.`m_group_item` (`id`, `group_type`, `group_id`, `group_code`, `child_type`, `child_id`, `child_code`, `enable_flag`, `create_by`, `create_on`, `update_by`, `update_on`) VALUES (1980188905231749120, 'CG', 1, 'COMPANY-GROUP', 'C', 1980185872708014080, 'HOUSE_ACCOUNT', 1, 'afe', '2025-10-20 16:26:40', 'afe', '2025-10-20 16:26:40');
-- ===============================
-- 初始化 g3fo_user 用户与交易权限
-- ===============================
REPLACE INTO `g3fo_user`.`m_user` (`id`, `user_code`, `local_name`, `eng_name`, `user_type`, `user_status`, `title`, `branch_code`, `department`, `mobile_no`, `email`, `create_by`, `create_on`, `update_by`, `update_on`, `trade_oddlot_flag`, `max_client_pct`, `single_override_limit_pct`, `max_deduct_pct`, `single_order_limit`, `single_override_limit`, `daily_override_limit`, `exposure_limit`, `cny_max_client_pct`, `cny_single_override_limit_pct`, `cny_single_order_limit`, `cny_single_override_limit`, `cny_daily_override_limit`, `otp_logon`, `otp_chgpwd`, `otp_method`, `credit_approval_role`, `effective_date`, `passport_id`, `delete_flag`, `delete_time`, `notification_opt`, `notification_method`, `change_password_flag`, `soft_key`, `reset_pass`, `mobile_device_id`, `mobile_platform_id`, `mobile_push_token`)
VALUES (1943512935934595072, 'APPSTORE1', 'APPSTORE1', 'APPSTORE1', 'CL', '0', '', 'DEFAULT', '5', '', 'man.zhong@afe.hk', 'sys', '2025-07-11 11:29:27', 'sys', '2025-10-14 13:26:59', 0, 20.000000, 100.000000, 0.000000, NULL, NULL, NULL, 0.00000000, 20.000000, 100.000000, NULL, NULL, NULL, 'DISD', 'DISD', 'SMS', 'NONE', '2025-07-11 11:28:46', '', 0, NULL, 'DISD', 'MOBI', 0, NULL, 'DISD', NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_user` (`id`, `user_code`, `local_name`, `eng_name`, `user_type`, `user_status`, `title`, `branch_code`, `department`, `mobile_no`, `email`, `create_by`, `create_on`, `update_by`, `update_on`, `trade_oddlot_flag`, `max_client_pct`, `single_override_limit_pct`, `max_deduct_pct`, `single_order_limit`, `single_override_limit`, `daily_override_limit`, `exposure_limit`, `cny_max_client_pct`, `cny_single_override_limit_pct`, `cny_single_order_limit`, `cny_single_override_limit`, `cny_daily_override_limit`, `otp_logon`, `otp_chgpwd`, `otp_method`, `credit_approval_role`, `effective_date`, `passport_id`, `delete_flag`, `delete_time`, `notification_opt`, `notification_method`, `change_password_flag`, `soft_key`, `reset_pass`, `mobile_device_id`, `mobile_platform_id`, `mobile_push_token`)
VALUES (1925469397361799170, 'afe', 'afe', 'afe', 'AE', '0', '', 'DEFAULT', '1', '', 'john.kong@afe.hk', 'sys', '2025-05-22 16:30:52', 'opr', '2025-10-14 13:26:59', 0, 20.000000, 100.000000, 0.000000, NULL, NULL, NULL, 0.00000000, 20.000000, 100.000000, NULL, NULL, NULL, 'DISD', 'ENG', 'NON', 'NONE', '2025-05-22 16:30:28', '', 0, NULL, 'TCHI', 'EMAL', 0, NULL, 'ENG', NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_user` (`id`, `user_code`, `local_name`, `eng_name`, `user_type`, `user_status`, `title`, `branch_code`, `department`, `mobile_no`, `email`, `create_by`, `create_on`, `update_by`, `update_on`, `trade_oddlot_flag`, `max_client_pct`, `single_override_limit_pct`, `max_deduct_pct`, `single_order_limit`, `single_override_limit`, `daily_override_limit`, `exposure_limit`, `cny_max_client_pct`, `cny_single_override_limit_pct`, `cny_single_order_limit`, `cny_single_override_limit`, `cny_daily_override_limit`, `otp_logon`, `otp_chgpwd`, `otp_method`, `credit_approval_role`, `effective_date`, `passport_id`, `delete_flag`, `delete_time`, `notification_opt`, `notification_method`, `change_password_flag`, `soft_key`, `reset_pass`, `mobile_device_id`, `mobile_platform_id`, `mobile_push_token`) VALUES (1978367120546861056, 'g2sfsupport', 'g2sfsupport', 'g2sfsupport', 'AE', '0', '', 'DEFAULT', '1', '6800-8690', 'g2sfsupport@afe.hk', 'afe', '2025-10-15 15:47:32', 'sys', '2025-10-18 11:20:29', 0, 20.000000, 100.000000, 0.000000, NULL, NULL, NULL, 0.00000000, 20.000000, 100.000000, NULL, NULL, NULL, 'DISD', 'DISD', 'NON', 'NONE', '2025-10-15 15:46:45', '', 0, NULL, 'DISD', 'EMAL', 0, NULL, 'DISD', NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_user` (`id`, `user_code`, `local_name`, `eng_name`, `user_type`, `user_status`, `title`, `branch_code`, `department`, `mobile_no`, `email`, `create_by`, `create_on`, `update_by`, `update_on`, `trade_oddlot_flag`, `max_client_pct`, `single_override_limit_pct`, `max_deduct_pct`, `single_order_limit`, `single_override_limit`, `daily_override_limit`, `exposure_limit`, `cny_max_client_pct`, `cny_single_override_limit_pct`, `cny_single_order_limit`, `cny_single_override_limit`, `cny_daily_override_limit`, `otp_logon`, `otp_chgpwd`, `otp_method`, `credit_approval_role`, `effective_date`, `passport_id`, `delete_flag`, `delete_time`, `notification_opt`, `notification_method`, `change_password_flag`, `soft_key`, `reset_pass`, `mobile_device_id`, `mobile_platform_id`, `mobile_push_token`) VALUES (1980073989309075456, 'g3sfsupport', 'g3sfsupport', 'g3sfsupport', 'AE', '0', NULL, 'DEFAULT', '1', NULL, 'g2sfsupport@afe.hk', 'afe', '2025-10-20 08:50:02', 'afe', '2025-10-20 08:49:12', 0, 20.000000, 100.000000, 0.000000, NULL, NULL, NULL, 0.00000000, 20.000000, 100.000000, NULL, NULL, NULL, 'DISD', 'DISD', 'NON', 'NONE', '2025-10-20 08:49:12', NULL, 0, NULL, 'DISD', NULL, 0, NULL, 'DISD', NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_user` (`id`, `user_code`, `local_name`, `eng_name`, `user_type`, `user_status`, `title`, `branch_code`, `department`, `mobile_no`, `email`, `create_by`, `create_on`, `update_by`, `update_on`, `trade_oddlot_flag`, `max_client_pct`, `single_override_limit_pct`, `max_deduct_pct`, `single_order_limit`, `single_override_limit`, `daily_override_limit`, `exposure_limit`, `cny_max_client_pct`, `cny_single_override_limit_pct`, `cny_single_order_limit`, `cny_single_override_limit`, `cny_daily_override_limit`, `otp_logon`, `otp_chgpwd`, `otp_method`, `credit_approval_role`, `effective_date`, `passport_id`, `delete_flag`, `delete_time`, `notification_opt`, `notification_method`, `change_password_flag`, `soft_key`, `reset_pass`, `mobile_device_id`, `mobile_platform_id`, `mobile_push_token`) VALUES (1980074724268576768, 'szg3sfsupport', 'szg3sfsupport', 'szg3sfsupport', 'AE', '0', NULL, 'DEFAULT', '1', NULL, 'g2sfsupport@afe.hk', 'afe', '2025-10-20 08:52:57', 'afe', '2025-10-20 08:52:22', 0, 20.000000, 100.000000, 0.000000, NULL, NULL, NULL, 0.00000000, 20.000000, 100.000000, NULL, NULL, NULL, 'DISD', 'DISD', 'NON', 'NONE', '2025-10-20 08:52:22', NULL, 0, NULL, 'DISD', 'EMAL', 0, NULL, 'DISD', NULL, NULL, NULL);
REPLACE INTO `g3fo_user`.`m_user_client_relations` (`id`, `parent_type`, `parent_user_id`, `parent_user_code`, `child_type`, `child_id`, `child_code`, `enable_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1925478879873642498, 'U', 1925469397361799170, 'afe', 'C', 1, 'afe', 1, 'sys', '2025-05-22 17:08:33', 'sys', '2025-05-22 17:08:33');
REPLACE INTO `g3fo_user`.`m_user_client_relations` (`id`, `parent_type`, `parent_user_id`, `parent_user_code`, `child_type`, `child_id`, `child_code`, `enable_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1943514529233244160, 'U', 1943512935934595072, 'APPSTORE1', 'C', 1943513539612381184, 'APPSTORE1', 1, 'sys', '2025-07-11 11:35:47', 'sys', '2025-07-11 11:35:47');
REPLACE INTO `g3fo_user`.`m_user_client_relations` (`id`, `parent_type`, `parent_user_id`, `parent_user_code`, `child_type`, `child_id`, `child_code`, `enable_flag`, `create_by`, `create_on`, `update_by`, `update_on`) VALUES (1980091573093928960, 'U', 1980074724268576768, 'szg3sfsupport', 'CG', 1, 'COMPANY-GROUP', 1, 'sys', '2025-10-20 09:59:54', 'sys', '2025-10-20 09:59:54');
REPLACE INTO `g3fo_user`.`m_user_client_relations` (`id`, `parent_type`, `parent_user_id`, `parent_user_code`, `child_type`, `child_id`, `child_code`, `enable_flag`, `create_by`, `create_on`, `update_by`, `update_on`) VALUES (1980116781104238592, 'U', 1980073989309075456, 'g3sfsupport', 'U', 1978367120546861056, 'g2sfsupport', 1, 'opr', '2025-10-20 11:40:04', 'opr', '2025-10-20 11:40:04');
REPLACE INTO `g3fo_user`.`m_user_trade_license` (`id`, `user_id`, `exchange_code`, `market_ids`, `active_flag`, `create_on`, `create_by`, `update_on`, `update_by`)
VALUES (1925469430924619778, 1925469397361799170, 'SEHK', '1,7,8,9', 1, '2025-05-22 16:31:00', 'sys', '2025-05-22 16:31:00', 'sys');
REPLACE INTO `g3fo_user`.`m_user_trade_license` (`id`, `user_id`, `exchange_code`, `market_ids`, `active_flag`, `create_on`, `create_by`, `update_on`, `update_by`)
VALUES (1943512964262924288, 1943512935934595072, 'SEHK', '1,7,8,9', 1, '2025-07-11 11:29:34', 'sys', '2025-07-11 11:29:34', 'sys');
REPLACE INTO `g3fo_user`.`t_user_account_ref` (`user_id`, `account_id`, `create_on`)
VALUES (1925469397361799170, 1, '2025-09-03 16:40:50');
REPLACE INTO `g3fo_user`.`t_user_child_user_ref` (`user_id`, `child_user_id`, `create_on`)
VALUES (1925469397361799170, 1925469397361799170, '2025-09-03 16:40:50');
REPLACE INTO `g3fo_user`.`t_user_client_ref` (`user_id`, `client_id`, `create_on`)
VALUES (1925469397361799170, 1, '2025-09-03 16:40:50');
-- ===============================
-- 初始化 g3fo_user 登录与角色
-- ===============================
REPLACE INTO `g3fo_user`.`m_user_login` (`id`, `user_id`, `user_code`, `channel_code`, `login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`, `suspense_flag`, `enable_dt_info_flag`, `mult_session_flag`, `info_package_id`, `next_remind_date`, `remind_day`, `change_pwd_date`, `token`)
VALUES (1943513267687264256, 1943512935934595072, 'APPSTORE1', 'WS', NULL, 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, '2026-01-08 14:58:12', NULL, 'sys', '2025-07-11 11:30:46', 'sys', '2025-10-15 09:30:18', 0, NULL, 1, '', '2025-12-09 14:58:12', NULL, '2025-10-10 14:58:12', NULL);
REPLACE INTO `g3fo_user`.`m_user_login` (`id`, `user_id`, `user_code`, `channel_code`, `login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`, `suspense_flag`, `enable_dt_info_flag`, `mult_session_flag`, `info_package_id`, `next_remind_date`, `remind_day`, `change_pwd_date`, `token`)
VALUES (1962711560971489280, 1943512935934595072, 'APPSTORE1', 'IH', NULL, 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, '2026-01-08 14:58:12', NULL, 'L_TANG', '2025-09-02 10:57:56', 'afe', '2025-10-13 17:29:37', 0, NULL, 1, '443', '2025-12-09 14:58:12', NULL, '2025-10-10 14:58:12', NULL);
REPLACE INTO `g3fo_user`.`m_user_login` (`id`, `user_id`, `user_code`, `channel_code`, `login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`, `suspense_flag`, `enable_dt_info_flag`, `mult_session_flag`, `info_package_id`, `next_remind_date`, `remind_day`, `change_pwd_date`, `token`)
VALUES (1925469490802503681, 1925469397361799170, 'afe', 'IN', NULL, 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, '2025-11-23 11:38:06', NULL, 'sys', '2025-05-22 16:31:15', 'sys', '2025-08-25 11:38:05', 0, NULL, 1, NULL, '2025-10-24 11:38:06', NULL, '2025-08-25 11:38:06', NULL);
REPLACE INTO `g3fo_user`.`m_user_login` (`id`, `user_id`, `user_code`, `channel_code`, `login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`, `suspense_flag`, `enable_dt_info_flag`, `mult_session_flag`, `info_package_id`, `next_remind_date`, `remind_day`, `change_pwd_date`, `token`)
VALUES (1925470040684146690, 1925469397361799170, 'afe', 'PT', NULL, 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, '2025-11-23 11:38:06', NULL, 'sys', '2025-05-22 16:33:26', 'afe', '2025-08-25 11:38:05', 0, NULL, 1, '', '2025-10-24 11:38:06', NULL, '2025-08-25 11:38:06', NULL);
REPLACE INTO `g3fo_user`.`m_user_login` (`id`, `user_id`, `user_code`, `channel_code`, `login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`, `suspense_flag`, `enable_dt_info_flag`, `mult_session_flag`, `info_package_id`, `next_remind_date`, `remind_day`, `change_pwd_date`, `token`)
VALUES (1978367310318145536, 1978367120546861056, 'g2sfsupport', 'PT', NULL, '16AFD883D4C47276FB9410E521A1B227DA0D8F5FE02D0C3E54145D9815FCBE11', 0, '2026-01-16 09:57:30', NULL, 'afe', '2025-10-15 15:48:18', 'afe', '2025-11-03 16:16:43', 0, NULL, 1, '', '2025-12-17 09:57:30', NULL, '2025-10-18 09:57:30', NULL);
REPLACE INTO `g3fo_user`.`m_user_login` (`id`, `user_id`, `user_code`, `channel_code`, `login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`, `suspense_flag`, `enable_dt_info_flag`, `mult_session_flag`, `info_package_id`, `next_remind_date`, `remind_day`, `change_pwd_date`, `token`)
VALUES (1980074162877763584, 1980073989309075456, 'g3sfsupport', 'PT', NULL, 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, '2026-01-18 08:50:43', NULL, 'afe', '2025-10-20 08:50:43', 'afe', '2025-10-21 15:13:28', 0, NULL, 1, '', '2025-12-19 08:50:43', NULL, '2025-10-20 08:50:43', NULL);
REPLACE INTO `g3fo_user`.`m_user_login` (`id`, `user_id`, `user_code`, `channel_code`, `login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`, `suspense_flag`, `enable_dt_info_flag`, `mult_session_flag`, `info_package_id`, `next_remind_date`, `remind_day`, `change_pwd_date`, `token`)
VALUES (1980074798025412608, 1980074724268576768, 'szg3sfsupport', 'PT', NULL, 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, '2026-01-18 08:53:15', NULL, 'afe', '2025-10-20 08:53:15', 'afe', '2025-10-20 08:53:14', 0, NULL, 1, '', '2025-12-19 08:53:15', NULL, '2025-10-20 08:53:15', NULL);
REPLACE INTO `g3fo_user`.`m_user_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1943512984248782848, 1943512935934595072, 'APPSTORE1', 9, 1, 'sys', '2025-07-11 11:29:39', 'sys', '2025-07-11 11:29:39');
REPLACE INTO `g3fo_user`.`m_user_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1962711775682105344, 1943512935934595072, 'APPSTORE1', 10, 1, 'L_TANG', '2025-09-02 10:58:47', 'L_TANG', '2025-09-02 10:58:47');
REPLACE INTO `g3fo_user`.`m_user_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1925469448863657985, 1925469397361799170, 'afe', 1, 1, 'sys', '2025-05-22 16:31:05', 'sys', '2025-05-22 16:31:05');
REPLACE INTO `g3fo_user`.`m_user_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1959823319108816896, 1925469397361799170, 'afe', 2, 1, 'afe', '2025-08-25 11:41:06', 'afe', '2025-08-25 11:41:06');
REPLACE INTO `g3fo_user`.`m_user_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1978734167583756288, 1978367120546861056, 'g2sfsupport', 1, 1, 'sys', '2025-10-16 16:06:03', 'sys', '2025-10-16 16:06:03');
REPLACE INTO `g3fo_user`.`m_user_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1980074075913064448, 1980073989309075456, 'g3sfsupport', 1, 1, 'afe', '2025-10-20 08:50:22', 'afe', '2025-10-20 08:50:22');
REPLACE INTO `g3fo_user`.`m_user_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1980074746255118336, 1980074724268576768, 'szg3sfsupport', 1, 1, 'afe', '2025-10-20 08:53:02', 'afe', '2025-10-20 08:53:02');
-- ===============================
-- 初始化 g3fo_admin 管理员
-- ===============================
REPLACE INTO `g3fo_admin`.`m_admin` (`id`, `user_code`, `local_name`, `eng_name`, `user_type`, `user_status`, `title`, `branch_code`, `department`, `mobile_no`, `email`, `expiry_date`, `create_by`, `create_on`, `update_by`, `update_on`, `otp_logon`, `otp_method`, `soft_key`, `passport_id`)
VALUES (1, 'sys', 'sys', 'sys', '1', '0', '', '', '4', '', 'man.zhong@afe.hk', '2030-12-31 14:59:32', 'sys', '2023-09-06 14:59:40', '2', '2025-05-22 17:16:47', '', '', '', '');
REPLACE INTO `g3fo_admin`.`m_admin` (`id`, `user_code`, `local_name`, `eng_name`, `user_type`, `user_status`, `title`, `branch_code`, `department`, `mobile_no`, `email`, `expiry_date`, `create_by`, `create_on`, `update_by`, `update_on`, `otp_logon`, `otp_method`, `soft_key`, `passport_id`)
VALUES (1927187036663549954, 'opr', 'opr', 'opr', '0', '0', '', '', '5', '', 'man.zhong@afe.hk', NULL, 'sys', '2025-05-27 10:16:09', 'sys', NULL, 'DISD', 'NON', NULL, '');
REPLACE INTO `g3fo_admin`.`m_admin` (`id`, `user_code`, `local_name`, `eng_name`, `user_type`, `user_status`, `title`, `branch_code`, `department`, `mobile_no`, `email`, `expiry_date`, `create_by`, `create_on`, `update_by`, `update_on`, `otp_logon`, `otp_method`, `soft_key`, `passport_id`)
VALUES (1927187170034028545, 'afe', 'afe', 'afe', '0', '0', '', '', '5', '', 'john.kong@afe.hk', NULL, 'sys', '2025-05-27 10:16:41', 'sys', '2025-05-30 14:13:18', 'ENG', 'NON', 'b99a24f0b2152335c17ec192970335b372a8dc5d', 'A123456');
REPLACE INTO `g3fo_admin`.`m_admin` (`id`, `user_code`, `local_name`, `eng_name`, `user_type`, `user_status`, `title`, `branch_code`, `department`, `mobile_no`, `email`, `expiry_date`, `create_by`, `create_on`, `update_by`, `update_on`, `otp_logon`, `otp_method`, `soft_key`, `passport_id`)
VALUES (1978983781352595458, 'g3bsupport', 'g3bsupport', 'g3bsupport', '0', '0', '', 'DEFAULT', '1', '', '', NULL, 'sys', '2025-10-17 08:37:55', 'sys', NULL, 'DISD', 'NON', NULL, '');
REPLACE INTO `g3fo_admin`.`m_admin_login` (`id`, `user_id`, `user_code`, `channel_code`, `admin_login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1, 1, 'sys', 'OM', '1', 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, '2023-09-06 15:02:48', '2023-09-06 15:02:51', '1', '2023-09-06 15:02:55', '1', '2023-09-06 15:02:59');
REPLACE INTO `g3fo_admin`.`m_admin_login` (`id`, `user_id`, `user_code`, `channel_code`, `admin_login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1927187036743241729, 1927187036663549954, 'opr', 'OM', '1', 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, NULL, NULL, NULL, NULL, NULL, NULL);
REPLACE INTO `g3fo_admin`.`m_admin_login` (`id`, `user_id`, `user_code`, `channel_code`, `admin_login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1927187170126303234, 1927187170034028545, 'afe', 'OM', '1', 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, NULL, NULL, NULL, NULL, NULL, NULL);
REPLACE INTO `g3fo_admin`.`m_admin_login` (`id`, `user_id`, `user_code`, `channel_code`, `admin_login_status`, `password`, `retry_count`, `pwd_expiry_date`, `last_login_date`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1978983781449064449, 1978983781352595458, 'g3bsupport', 'OM', '1', 'F877376BAD1A22E67333F299305674CDEC789F2BA2E5BFD074A6B40F0D245CDB', 0, NULL, NULL, NULL, NULL, NULL, NULL);
REPLACE INTO `g3fo_admin`.`m_admin_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1927187036705492994, 1927187036663549954, 'opr', 4, NULL, 'sys', '2025-05-27 10:16:10', 'sys', '2025-05-27 10:16:10');
REPLACE INTO `g3fo_admin`.`m_admin_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1927187170080165890, 1927187170034028545, 'afe', 4, NULL, 'sys', '2025-05-27 10:16:41', 'opr', '2025-05-30 14:13:19');
REPLACE INTO `g3fo_admin`.`m_admin_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1, 1, 'sys', 4, NULL, 'sys', '2023-11-13 09:37:56', 'sys', '2025-05-22 17:16:47');
REPLACE INTO `g3fo_admin`.`m_admin_role_relation_def` (`id`, `user_id`, `user_code`, `user_role_templates_id`, `active_flag`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES (1978983781377761282, 1978983781352595458, 'g3bsupport', 4, NULL, 'sys', '2025-10-17 08:37:56', 'sys', '2025-10-17 08:37:56');
-- ===============================
-- 市场 API 会话与系统参数更新
-- ===============================
UPDATE `g3fo_base`.`m_exchange`
SET `market_session_code` = 'OCG';
DELETE FROM `g3fo_base`.`m_market_api_session_info`;
INSERT INTO `g3fo_base`.`m_market_api_session_info` (`id`, `market_api_info_id`, `session_code`, `exchange_code`, `sender_comp_id`, `target_comp_id`, `rsakey`, `username`, `password`, `new_password`, `broker_list`, `auto_sync_seq_num_flag`, `auto_get_broker_id_flag`, `throttle_limit`, `remark`, `create_on`, `create_by`, `update_on`, `update_by`)
VALUES (1, 1, 'OCG', 'SEHK', 'CO01433001', 'HKEXCO', 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3bn6Y9Uz6lmtQZXl3cQnTshv8G3X8F3G35p1gdAD1pphD6FzfYnrwxrzqrbu27x4RQ9MpACi/8ct7OmyKiW06jekCJAGuy5EpHJWLnjYJS0ZcpYEQLfg3dEoY1X8J1S5S8oK0DVfk5gQrtyS9XOhU7D8aJbF6O/rZU5U5Nz/2p7e87sZeWAQigntFYN4pn68TkFzaVcoL7o4RN9AnQtDyXJcxwnP0bZxiOxOft5Jj6UB0I/5SOCZF61c9xxsd8fA3JkSTmudO80bnSwsmJZO7oCvu6R3FlHTWy8lZNwH0Wo5kaMCvKrn1i72fcUVVN5OcdmFIl+Yj3PqRGLIhGzM6wIDAQAB', NULL, 'Hw171025', 'Hw171025', '1399,1390,1391,1398', 0, 1, 0, '', NOW(), NULL, NOW(), 'sys');
INSERT INTO `g3fo_base`.`m_market_api_session_info` (`id`, `market_api_info_id`, `session_code`, `exchange_code`, `sender_comp_id`, `target_comp_id`, `rsakey`, `username`, `password`, `new_password`, `broker_list`, `auto_sync_seq_num_flag`, `auto_get_broker_id_flag`, `throttle_limit`, `remark`, `create_on`, `create_by`, `update_on`, `update_by`)
VALUES (2, 1, 'OCG-DC', 'SEHK', 'CC01433001', 'HKEXCC', 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3bn6Y9Uz6lmtQZXl3cQnTshv8G3X8F3G35p1gdAD1pphD6FzfYnrwxrzqrbu27x4RQ9MpACi/8ct7OmyKiW06jekCJAGuy5EpHJWLnjYJS0ZcpYEQLfg3dEoY1X8J1S5S8oK0DVfk5gQrtyS9XOhU7D8aJbF6O/rZU5U5Nz/2p7e87sZeWAQigntFYN4pn68TkFzaVcoL7o4RN9AnQtDyXJcxwnP0bZxiOxOft5Jj6UB0I/5SOCZF61c9xxsd8fA3JkSTmudO80bnSwsmJZO7oCvu6R3FlHTWy8lZNwH0Wo5kaMCvKrn1i72fcUVVN5OcdmFIl+Yj3PqRGLIhGzM6wIDAQAB', NULL, 'Hw171025', 'Hw171025', '1399,1390,1391,1398', 0, 1, 0, '', NOW(), NULL, NOW(), 'sys');
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '3082014B0201003082012C06072A8648CE3804013082011F02818100FD7F53811D75122952DF4A9C2EECE4E7F611B7523CEF4400C31E3F80B6512669455D402251FB593D8D58FABFC5F5BA30F6CB9B556CD7813B801D346FF26660B76B9950A5A49F9FE8047B1022C24FBBA9D7FEB7C61BF83B57E7C6A8A6150F04FB83F6D3C51EC3023554135A169132F675F3AE2B61D72AEFF22203199DD14801C70215009760508F15230BCCB292B982A2EB840BF0581CF502818100F7E1A085D69B3DDECBBCAB5C36B857B97994AFBBFA3AEA82F9574C0B3D0782675159578EBAD4594FE67107108180B449167123E84C281613B7CF09328CC8A6E13C167A8B547C8D28E0A3AE1E2BB3A675916EA37F0BFA213562F1FB627A01243BCCA4F1BEA8519089A883DFE15AE59F06928B665E807B552564014C3BFECF492A041602141FD4151E4E63E45D0E480CC880E04E0E4746F393',
`description_i18n_id` = NULL,
`remark` = 'Infobase Single Logon Private Key',
`create_by` = 'ken',
`create_on` = '2024-02-22 09:21:43',
`update_by` = 'ken',
`update_on` = NOW()
WHERE `param_name` = 'base.infoBaseLogonKey';
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = '683',
`description_i18n_id` = NULL,
`remark` = 'Site ID for Single pass Logon',
`create_by` = 'ken',
`create_on` = '2024-02-22 09:18:26',
`update_by` = 'ken',
`update_on` = NOW()
WHERE `param_name` = 'base.siteId';
UPDATE `g3fo_base`.`m_system_setting`
SET `param_value` = 'hingwai',
`description_i18n_id` = NULL,
`remark` = 'Site Name (group name required)',
`create_by` = 'ken',
`create_on` = '2024-02-22 09:18:06',
`update_by` = 'ken',
`update_on` = NOW()
WHERE `param_name` = 'base.siteName';
@@ -0,0 +1,287 @@
USE g3fo_base;
-- ===================================================================
-- 存储过程:插入系统菜单数据
-- 功能:
-- 1. 自动生成ID(最大ID+1)并插入系统菜单记录
-- 2. 当menu_type为'ADMIN'时,自动为所有管理员角色模板创建权限记录
-- 3. 当menu_type为'USER'时,自动为所有用户角色模板创建权限记录
-- 4. 数据去重检查:
-- - m_system_menus: 检查 menu_name + menu_type 组合
-- - m_admin_role_rights: 检查 user_role_templates_id + user_right_id + user_right_type 组合
-- - m_user_role_rights: 检查 user_role_templates_id + user_right_id + user_right_type 组合
-- 参数:
-- p_remark: 备注
-- p_menu_name: 菜单名称
-- p_title_remark: 标题备注
-- p_menu_type: 菜单类型('ADMIN' 或 'USER')
-- p_description_i18n_id: 描述国际化ID(可选,默认为NULL)
-- p_active_flag: 激活标志(可选,默认为1)
-- ===================================================================
DROP PROCEDURE IF EXISTS InsertSystemMenu;
DELIMITER $$
CREATE PROCEDURE InsertSystemMenu(
IN p_remark VARCHAR(50),
IN p_menu_name VARCHAR(255),
IN p_title_remark VARCHAR(50),
IN p_menu_type CHAR(8),
IN p_description_i18n_id CHAR(32),
IN p_active_flag SMALLINT
)
proc_label: BEGIN
DECLARE v_new_menu_id INT;
DECLARE v_done INT DEFAULT FALSE;
DECLARE v_template_id BIGINT;
DECLARE v_new_right_id INT;
DECLARE v_rights_count INT DEFAULT 0;
DECLARE v_existing_menu_id INT DEFAULT NULL;
DECLARE v_existing_right_count INT DEFAULT 0;
-- 声明游标结束处理器
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
-- ============================================================
-- 第一步:检查菜单是否已存在(menu_name + menu_type 组合去重)
-- ============================================================
SELECT id INTO v_existing_menu_id
FROM g3fo_base.m_system_menus
WHERE menu_name = p_menu_name AND menu_type = p_menu_type
LIMIT 1;
-- 如果菜单已存在,直接退出存储过程
IF v_existing_menu_id IS NOT NULL THEN
LEAVE proc_label; -- 退出存储过程
END IF;
-- ============================================================
-- 第二步:插入系统菜单数据
-- ============================================================
-- 获取当前最大ID并加1
SELECT COALESCE(MAX(id), 0) + 1 INTO v_new_menu_id
FROM g3fo_base.m_system_menus;
-- 设置默认值
IF p_active_flag IS NULL THEN
SET p_active_flag = 1;
END IF;
-- 插入系统菜单数据
INSERT INTO g3fo_base.m_system_menus (
id,
remark,
menu_name,
description_i18n_id,
active_flag,
title_remark,
menu_type,
create_by,
create_on,
update_by,
update_on
) VALUES (
v_new_menu_id,
p_remark,
p_menu_name,
p_description_i18n_id,
p_active_flag,
p_title_remark,
p_menu_type,
'sys',
NOW(),
'sys',
NOW()
);
-- ============================================================
-- 第三步:根据menu_type创建相应的角色权限记录
-- ============================================================
IF UPPER(p_menu_type) = 'ADMIN' THEN
-- ========================================================
-- 为管理员角色模板创建权限记录
-- ========================================================
BEGIN
DECLARE admin_cursor CURSOR FOR
SELECT id FROM g3fo_admin.m_admin_role_templates;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
SET v_done = FALSE;
OPEN admin_cursor;
admin_loop: LOOP
FETCH admin_cursor INTO v_template_id;
IF v_done THEN
LEAVE admin_loop;
END IF;
-- 检查该权限记录是否已存在(去重检查)
SET v_existing_right_count = 0;
SELECT COUNT(*) INTO v_existing_right_count
FROM g3fo_admin.m_admin_role_rights
WHERE user_role_templates_id = v_template_id
AND user_right_id = v_new_menu_id
AND user_right_type = 'MENU';
-- 只有当权限记录不存在时才插入
IF v_existing_right_count = 0 THEN
-- 获取当前最大的权限ID并加1
SELECT COALESCE(MAX(id), 0) + 1 INTO v_new_right_id
FROM g3fo_admin.m_admin_role_rights;
-- 插入管理员角色权限记录
INSERT INTO g3fo_admin.m_admin_role_rights (
id,
user_role_templates_id,
user_right_id,
user_right_type,
create_on,
update_on
) VALUES (
v_new_right_id,
v_template_id,
v_new_menu_id,
'MENU',
NOW(),
NOW()
);
SET v_rights_count = v_rights_count + 1;
END IF;
END LOOP;
CLOSE admin_cursor;
END;
ELSEIF UPPER(p_menu_type) = 'USER' THEN
-- ========================================================
-- 为用户角色模板创建权限记录(排除id=9)
-- ========================================================
BEGIN
DECLARE user_cursor CURSOR FOR
SELECT id FROM g3fo_user.m_user_role_templates WHERE id != 9;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
SET v_done = FALSE;
OPEN user_cursor;
user_loop: LOOP
FETCH user_cursor INTO v_template_id;
IF v_done THEN
LEAVE user_loop;
END IF;
-- 检查该权限记录是否已存在(去重检查)
SET v_existing_right_count = 0;
SELECT COUNT(*) INTO v_existing_right_count
FROM g3fo_user.m_user_role_rights
WHERE user_role_templates_id = v_template_id
AND user_right_id = v_new_menu_id
AND user_right_type = 'MENU';
-- 只有当权限记录不存在时才插入
IF v_existing_right_count = 0 THEN
-- 获取当前最大的权限ID并加1
SELECT COALESCE(MAX(id), 0) + 1 INTO v_new_right_id
FROM g3fo_user.m_user_role_rights;
-- 插入用户角色权限记录
INSERT INTO g3fo_user.m_user_role_rights (
id,
user_role_templates_id,
user_right_id,
user_right_type,
create_on,
update_on
) VALUES (
v_new_right_id,
v_template_id,
v_new_menu_id,
'MENU',
NOW(),
NOW()
);
SET v_rights_count = v_rights_count + 1;
END IF;
END LOOP;
CLOSE user_cursor;
END;
END IF;
-- ============================================================
-- 返回结果
-- ============================================================
END$$
DELIMITER ;
-- ===================================================================
-- 在这里添加需要插入的菜单
-- ===================================================================
-- CALL InsertSystemMenu('菜单备注', 'menu-name', 'title_remark', 'ADMIN', NULL, 1);
-- CALL InsertSystemMenu('菜单备注', 'menu-name', 'title_remark', 'USER', NULL, 1);
-- ===================================================================
-- 使用示例:
-- ===================================================================
-- 示例1: 插入管理员菜单(会在 m_system_menus 中插入一条记录,
-- 同时在 m_admin_role_rights 中为所有管理员角色模板创建权限记录)
-- CALL InsertSystemMenu('用户管理', 'user-management', 'user', 'ADMIN', NULL, 1);
-- 示例2: 插入用户菜单(会在 m_system_menus 中插入一条记录,
-- 同时在 m_user_role_rights 中为所有用户角色模板(除了id=9)创建权限记录)
-- CALL InsertSystemMenu('订单查询', 'order-query', 'order', 'USER', NULL, 1);
-- 示例3: 插入带国际化ID的管理员菜单
-- CALL InsertSystemMenu('报表管理', 'report-management', 'report', 'ADMIN', 'REPORT-0001', 1);
-- ===================================================================
-- 说明:
-- ===================================================================
-- 当 menu_type = 'ADMIN' 时:
-- - 在 g3fo_base.m_system_menus 中插入一条菜单记录
-- - 自动获取 g3fo_admin.m_admin_role_templates 中所有id
-- - 为每个角色模板在 g3fo_admin.m_admin_role_rights 中创建一条权限记录
-- * id: 自动递增(最大ID + 1)
-- * user_role_templates_id: 角色模板ID
-- * user_right_id: 新插入的菜单ID
-- * user_right_type: 'MENU'
--
-- 当 menu_type = 'USER' 时:
-- - 在 g3fo_base.m_system_menus 中插入一条菜单记录
-- - 自动获取 g3fo_user.m_user_role_templates 中所有id(排除 id=9)
-- - 为每个角色模板在 g3fo_user.m_user_role_rights 中创建一条权限记录
-- * id: 自动递增(最大ID + 1)
-- * user_role_templates_id: 角色模板ID
-- * user_right_id: 新插入的菜单ID
-- * user_right_type: 'MENU'
--
-- 去重逻辑:
-- 1. 菜单去重:如果 menu_name + menu_type 组合已存在,返回错误,不插入任何数据
-- 2. 权限去重:对于每个角色模板,检查 user_role_templates_id + user_right_id + user_right_type
-- 组合是否已存在,如果已存在则跳过该条记录,继续处理下一个
--
-- 参数说明:
-- p_remark: 菜单备注(varchar(50))
-- p_menu_name: 菜单名称,唯一标识(varchar(255))
-- p_title_remark: 标题备注(varchar(50))
-- p_menu_type: 菜单类型,'ADMIN' 或 'USER'(char(8))
-- p_description_i18n_id: 描述国际化ID,可选(char(32)),默认为NULL
-- p_active_flag: 激活标志,可选(smallint),默认为1
-- ===================================================================
@@ -0,0 +1,272 @@
USE g3fo_base;
-- ===================================================================
-- 存储过程:插入系统路由数据
-- 功能:
-- 1. 自动生成ID(最大ID+1,最小从7000开始)并插入系统路由记录
-- 2. 当route_type为'ADMIN'时,自动为所有管理员角色模板创建权限记录
-- 3. 当route_type为'USER'时,自动为所有用户角色模板创建权限记录
-- 4. 数据去重检查:
-- - m_system_routes: 检查 route + route_type 组合
-- - m_admin_role_rights: 检查 user_role_templates_id + user_right_id + user_right_type 组合
-- - m_user_role_rights: 检查 user_role_templates_id + user_right_id + user_right_type 组合
-- 参数:
-- p_remark: 备注
-- p_route: 路由地址
-- p_title_remark: 标题备注
-- p_route_type: 路由类型('ADMIN' 或 'USER')
-- ===================================================================
DROP PROCEDURE IF EXISTS InsertSystemRoute;
DELIMITER $$
CREATE PROCEDURE InsertSystemRoute(
IN p_remark VARCHAR(50),
IN p_route VARCHAR(255),
IN p_title_remark VARCHAR(50),
IN p_route_type CHAR(8)
)
proc_label: BEGIN
DECLARE v_new_route_id INT;
DECLARE v_done INT DEFAULT FALSE;
DECLARE v_template_id BIGINT;
DECLARE v_new_right_id INT;
DECLARE v_rights_count INT DEFAULT 0;
DECLARE v_existing_route_id INT DEFAULT NULL;
DECLARE v_existing_right_count INT DEFAULT 0;
-- 声明游标结束处理器
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
-- ============================================================
-- 第一步:检查路由是否已存在(route + route_type 组合去重)
-- ============================================================
SELECT id INTO v_existing_route_id
FROM g3fo_base.m_system_routes
WHERE route = p_route AND route_type = p_route_type
LIMIT 1;
-- 如果路由已存在,直接返回错误信息
IF v_existing_route_id IS NOT NULL THEN
LEAVE proc_label; -- 退出存储过程
END IF;
-- ============================================================
-- 第二步:插入系统路由数据
-- ============================================================
-- 获取当前最大ID并加1
SELECT COALESCE(MAX(id), 6999) + 1 INTO v_new_route_id
FROM g3fo_base.m_system_routes;
-- 如果ID少于7000,从7000开始
IF v_new_route_id < 7000 THEN
SET v_new_route_id = 7000;
END IF;
-- 插入系统路由数据
INSERT INTO g3fo_base.m_system_routes (
id,
remark,
route,
title_remark,
route_type,
active_flag,
create_on,
update_on
) VALUES (
v_new_route_id,
p_remark,
p_route,
p_title_remark,
p_route_type,
1, -- 默认激活状态
NOW(),
NOW()
);
-- ============================================================
-- 第三步:根据route_type创建相应的角色权限记录
-- ============================================================
IF UPPER(p_route_type) = 'ADMIN' THEN
-- ========================================================
-- 为管理员角色模板创建权限记录
-- ========================================================
BEGIN
DECLARE admin_cursor CURSOR FOR
SELECT id FROM g3fo_admin.m_admin_role_templates;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
SET v_done = FALSE;
OPEN admin_cursor;
admin_loop: LOOP
FETCH admin_cursor INTO v_template_id;
IF v_done THEN
LEAVE admin_loop;
END IF;
-- 检查该权限记录是否已存在(去重检查)
SET v_existing_right_count = 0;
SELECT COUNT(*) INTO v_existing_right_count
FROM g3fo_admin.m_admin_role_rights
WHERE user_role_templates_id = v_template_id
AND user_right_id = v_new_route_id
AND user_right_type = 'ROTE';
-- 只有当权限记录不存在时才插入
IF v_existing_right_count = 0 THEN
-- 获取当前最大的权限ID并加1
SELECT COALESCE(MAX(id), 0) + 1 INTO v_new_right_id
FROM g3fo_admin.m_admin_role_rights;
-- 插入管理员角色权限记录
INSERT INTO g3fo_admin.m_admin_role_rights (
id,
user_role_templates_id,
user_right_id,
user_right_type,
create_on,
update_on
) VALUES (
v_new_right_id,
v_template_id,
v_new_route_id,
'ROTE',
NOW(),
NOW()
);
SET v_rights_count = v_rights_count + 1;
END IF;
END LOOP;
CLOSE admin_cursor;
END;
ELSEIF UPPER(p_route_type) = 'USER' THEN
-- ========================================================
-- 为用户角色模板创建权限记录(排除id=9)
-- ========================================================
BEGIN
DECLARE user_cursor CURSOR FOR
SELECT id FROM g3fo_user.m_user_role_templates WHERE id != 9;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
SET v_done = FALSE;
OPEN user_cursor;
user_loop: LOOP
FETCH user_cursor INTO v_template_id;
IF v_done THEN
LEAVE user_loop;
END IF;
-- 检查该权限记录是否已存在(去重检查)
SET v_existing_right_count = 0;
SELECT COUNT(*) INTO v_existing_right_count
FROM g3fo_user.m_user_role_rights
WHERE user_role_templates_id = v_template_id
AND user_right_id = v_new_route_id
AND user_right_type = 'ROTE';
-- 只有当权限记录不存在时才插入
IF v_existing_right_count = 0 THEN
-- 获取当前最大的权限ID并加1
SELECT COALESCE(MAX(id), 0) + 1 INTO v_new_right_id
FROM g3fo_user.m_user_role_rights;
-- 插入用户角色权限记录
INSERT INTO g3fo_user.m_user_role_rights (
id,
user_role_templates_id,
user_right_id,
user_right_type,
create_on,
update_on
) VALUES (
v_new_right_id,
v_template_id,
v_new_route_id,
'ROTE',
NOW(),
NOW()
);
SET v_rights_count = v_rights_count + 1;
END IF;
END LOOP;
CLOSE user_cursor;
END;
END IF;
-- ============================================================
-- 返回结果
-- ============================================================
END$$
DELIMITER ;
-- ===================================================================
-- 在这里添加需要插入的路由
-- ===================================================================
CALL InsertSystemRoute('重试订单', '/trade/order/retryOrder', '订单', 'USER');
-- ===================================================================
-- 使用示例:
-- ===================================================================
-- 示例1: 插入管理员路由(会在 m_system_routes 中插入一条记录,
-- 同时在 m_admin_role_rights 中为所有管理员角色模板创建权限记录)
-- CALL InsertSystemRoute('用户管理', '/admin/user/list', '用户管理', 'ADMIN');
-- 示例2: 插入用户路由(会在 m_system_routes 中插入一条记录,
-- 同时在 m_user_role_rights 中为所有用户角色模板(除了id=9)创建权限记录)
-- CALL InsertSystemRoute('订单查询', '/user/order/list', '订单查询', 'USER');
-- ===================================================================
-- 说明:
-- ===================================================================
-- 当 route_type = 'ADMIN' 时:
-- - 在 g3fo_base.m_system_routes 中插入一条路由记录
-- - 自动获取 g3fo_admin.m_admin_role_templates 中所有id
-- - 为每个角色模板在 g3fo_admin.m_admin_role_rights 中创建一条权限记录
-- * id: 自动递增(最大ID + 1)
-- * user_role_templates_id: 角色模板ID
-- * user_right_id: 新插入的路由ID
-- * user_right_type: 'ROTE'
--
-- 当 route_type = 'USER' 时:
-- - 在 g3fo_base.m_system_routes 中插入一条路由记录
-- - 自动获取 g3fo_user.m_user_role_templates 中所有id(排除 id=9)
-- - 为每个角色模板在 g3fo_user.m_user_role_rights 中创建一条权限记录
-- * id: 自动递增(最大ID + 1)
-- * user_role_templates_id: 角色模板ID
-- * user_right_id: 新插入的路由ID
-- * user_right_type: 'ROTE'
--
-- 去重逻辑:
-- 1. 路由去重:如果 route + route_type 组合已存在,返回错误,不插入任何数据
-- 2. 权限去重:对于每个角色模板,检查 user_role_templates_id + user_right_id + user_right_type
-- 组合是否已存在,如果已存在则跳过该条记录,继续处理下一个
--
-- 返回结果:
-- - new_route_id: 新插入的路由ID
-- - route_type: 路由类型
-- - rights_created: 成功创建的权限记录数量
-- - status: 执行状态('Success' 或错误信息)
-- ===================================================================
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
REPLACE INTO `g3fo_base`.`m_system_code` (`id`, `code_type`, `code_value`, `description_i18n_id`, `remark`, `sort`, `create_by`, `create_on`, `update_by`, `update_on`) VALUES ('404', 'OrderType', '015', 'CODE-0404', 'PCA Order (VN)', '16', 'sys', '2023-12-14 15:40:51', 'sys', '2024-07-05 18:23:49');
REPLACE INTO `g3fo_base`.`m_system_i18n` (`id`, `en_description`, `sc_description`, `tc_description`, `vn_description`, `create_by`, `create_on`, `update_by`, `update_on`) VALUES ('CODE-0404', 'PCA', 'PCA', 'PCA', 'PCA', 'sys', '2024-06-27 10:43:29', 'sys', '2024-07-05 13:59:04');
-- 订单类型自动转换配置(初始为空值,需要时再启用)
REPLACE INTO `g3fo_base`.`m_system_setting`
(`param_name`, `param_value`, `description_i18n_id`, `remark`, `create_by`, `create_on`, `update_by`, `update_on`)
VALUES
('trade.orderTypeAutoConversion',
'04|02-03',
NULL,
'订单类型自动转换:格式为源类型1|源类型2-目标类型,例如04|02-03表示将LO和ELO转换为ALO',
'sys',
NOW(),
'sys',
NOW());
REPLACE INTO `g3fo_base`.`m_system_setting` (`param_name`, `param_value`, `remark`, `create_by`) VALUES ('trade.maxAuctionOrderPriceChangeRatio', '15@SEHK', '竞价限价单最大价格区间(%)', 'sys');
@@ -0,0 +1,163 @@
USE g3fo_trade;
DROP PROCEDURE IF EXISTS UpdateBrokerIdColumnLength;
CREATE PROCEDURE UpdateBrokerIdColumnLength()
BEGIN
-- 更新 m_order 表的 broker_id 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_order'
AND column_name = 'broker_id'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`m_order` MODIFY COLUMN `broker_id` VARCHAR(32) COMMENT '经纪商ID';
END IF;
-- 更新 m_order 表的 counter_party 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_order'
AND column_name = 'counter_party'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`m_order` MODIFY COLUMN `counter_party` VARCHAR(32) COMMENT '对手方';
END IF;
-- 更新 m_order_actions 表的 broker_id 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_order_actions'
AND column_name = 'broker_id'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`m_order_actions` MODIFY COLUMN `broker_id` VARCHAR(32) COMMENT '经纪商ID';
END IF;
-- 更新 m_order_actions 表的 counter_party 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_order_actions'
AND column_name = 'counter_party'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`m_order_actions` MODIFY COLUMN `counter_party` VARCHAR(32) COMMENT '对手方';
END IF;
-- 更新 h_order 表的 broker_id 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_order'
AND column_name = 'broker_id'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`h_order` MODIFY COLUMN `broker_id` VARCHAR(32) COMMENT '经纪商ID';
END IF;
-- 更新 h_order 表的 counter_party 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_order'
AND column_name = 'counter_party'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`h_order` MODIFY COLUMN `counter_party` VARCHAR(32) COMMENT '对手方';
END IF;
-- 更新 h_order_actions 表的 broker_id 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_order_actions'
AND column_name = 'broker_id'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`h_order_actions` MODIFY COLUMN `broker_id` VARCHAR(32) COMMENT '经纪商ID';
END IF;
-- 更新 h_order_actions 表的 counter_party 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_order_actions'
AND column_name = 'counter_party'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`h_order_actions` MODIFY COLUMN `counter_party` VARCHAR(32) COMMENT '对手方';
END IF;
-- 更新 m_trade 表的 broker_id 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_trade'
AND column_name = 'broker_id'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`m_trade` MODIFY COLUMN `broker_id` VARCHAR(32) COMMENT '经纪商ID';
END IF;
-- 更新 m_trade 表的 counter_broker_id 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'm_trade'
AND column_name = 'counter_broker_id'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`m_trade` MODIFY COLUMN `counter_broker_id` VARCHAR(32) COMMENT '对手经纪商ID';
END IF;
-- 更新 h_trade 表的 broker_id 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_trade'
AND column_name = 'broker_id'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`h_trade` MODIFY COLUMN `broker_id` VARCHAR(32) COMMENT '经纪商ID';
END IF;
-- 更新 h_trade 表的 counter_broker_id 字段长度从 VARCHAR(8) 到 VARCHAR(32)
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'g3fo_trade'
AND table_name = 'h_trade'
AND column_name = 'counter_broker_id'
AND data_type = 'varchar'
AND character_maximum_length = 8
) THEN
ALTER TABLE `g3fo_trade`.`h_trade` MODIFY COLUMN `counter_broker_id` VARCHAR(32) COMMENT '对手经纪商ID';
END IF;
END;
CALL UpdateBrokerIdColumnLength();
DROP PROCEDURE IF EXISTS UpdateBrokerIdColumnLength;
@@ -0,0 +1,30 @@
--- Nacos2.5.1 升级 Nacos3.1.1
ALTER TABLE `nacos`.`config_info` MODIFY COLUMN `encrypted_data_key` varchar(1024) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL DEFAULT '' COMMENT '密钥' AFTER `c_schema`;
ALTER TABLE `nacos`.`permissions` COLLATE = utf8mb4_0900_ai_ci;
ALTER TABLE `nacos`.`permissions` MODIFY COLUMN `role` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'role' FIRST;
ALTER TABLE `nacos`.`permissions` MODIFY COLUMN `resource` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'resource' AFTER `role`;
ALTER TABLE `nacos`.`permissions` MODIFY COLUMN `action` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'action' AFTER `resource`;
ALTER TABLE `nacos`.`roles` COLLATE = utf8mb4_0900_ai_ci;
ALTER TABLE `nacos`.`roles` MODIFY COLUMN `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'username' FIRST;
ALTER TABLE `nacos`.`roles` MODIFY COLUMN `role` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'role' AFTER `username`;
ALTER TABLE `nacos`.`users` COLLATE = utf8mb4_0900_ai_ci;
ALTER TABLE `nacos`.`users` MODIFY COLUMN `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'username' FIRST;
ALTER TABLE `nacos`.`users` MODIFY COLUMN `password` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'password' AFTER `username`;
DROP TABLE IF EXISTS `nacos`.`config_info_aggr`;
DROP TABLE IF EXISTS `nacos`.`config_info_beta`;
DROP TABLE IF EXISTS `nacos`.`config_info_tag`;
DROP TABLE IF EXISTS `nacos`.`flyway_schema_history`;