Jelajahi Sumber

股票信息导出优化

Zhangbw 3 bulan lalu
induk
melakukan
981b2eab85

+ 6 - 0
.gitignore

@@ -47,3 +47,9 @@ nbdist/
 !*/build/*.xml
 
 .flattened-pom.xml
+
+### Logs ###
+logs/
+
+### VS Code ###
+.vscode/

+ 56 - 0
ruoyi-modules/yp-miniapp/src/main/resources/sql/sys_config.sql

@@ -0,0 +1,56 @@
+/*
+ Navicat Premium Dump SQL
+
+ Source Server         : zbw
+ Source Server Type    : MySQL
+ Source Server Version : 80042 (8.0.42)
+ Source Host           : localhost:3306
+ Source Schema         : ry_vue_5.x
+
+ Target Server Type    : MySQL
+ Target Server Version : 80042 (8.0.42)
+ File Encoding         : 65001
+
+ Date: 30/12/2025 15:16:29
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for sys_config
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_config`;
+CREATE TABLE `sys_config`  (
+  `config_id` bigint NOT NULL COMMENT '参数主键',
+  `tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '000000' COMMENT '租户编号',
+  `config_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '参数名称',
+  `config_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '参数键名',
+  `config_value` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '参数键值',
+  `config_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'N' COMMENT '系统内置(Y是 N否)',
+  `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
+  `create_by` bigint NULL DEFAULT NULL COMMENT '创建者',
+  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+  `update_by` bigint NULL DEFAULT NULL COMMENT '更新者',
+  `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
+  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
+  PRIMARY KEY (`config_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '参数配置表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sys_config
+-- ----------------------------
+INSERT INTO `sys_config` VALUES (1, '000000', '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 103, 1, '2025-12-19 11:57:51', NULL, NULL, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow');
+INSERT INTO `sys_config` VALUES (2, '000000', '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 103, 1, '2025-12-19 11:57:51', NULL, NULL, '初始化密码 123456');
+INSERT INTO `sys_config` VALUES (3, '000000', '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 103, 1, '2025-12-19 11:57:51', NULL, NULL, '深色主题theme-dark,浅色主题theme-light');
+INSERT INTO `sys_config` VALUES (5, '000000', '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 103, 1, '2025-12-19 11:57:51', NULL, NULL, '是否开启注册用户功能(true开启,false关闭)');
+INSERT INTO `sys_config` VALUES (11, '000000', 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 103, 1, '2025-12-19 11:57:51', NULL, NULL, 'true:开启, false:关闭');
+INSERT INTO `sys_config` VALUES (100, '000000', '超短池订阅价格', 'payment.short.price', '0.01', 'N', 103, 1, '2025-12-29 16:47:32', NULL, NULL, '超短池订阅价格(元),有效期到当日24:00');
+INSERT INTO `sys_config` VALUES (101, '000000', '强势池订阅价格', 'payment.strong.price', '0.01', 'N', 103, 1, '2025-12-29 16:47:32', NULL, NULL, '强势池订阅价格(元),有效期1年');
+INSERT INTO `sys_config` VALUES (104, '000000', '微信支付商户号', 'payment.mch.id', '', 'N', 103, 1, '2025-12-29 17:24:57', NULL, NULL, '微信支付商户号MCHID');
+INSERT INTO `sys_config` VALUES (105, '000000', '微信支付APIv3密钥', 'payment.api.v3.key', '', 'N', 103, 1, '2025-12-29 17:24:57', NULL, NULL, '微信支付APIv3密钥');
+INSERT INTO `sys_config` VALUES (106, '000000', '支付证书文件路径', 'payment.cert.path', '', 'N', 103, 1, '2025-12-29 17:24:57', NULL, NULL, '微信支付证书文件路径(apiclient_cert.pem)');
+INSERT INTO `sys_config` VALUES (107, '000000', '支付回调地址', 'payment.notify.url', '', 'N', 103, 1, '2025-12-29 17:24:57', NULL, NULL, '微信支付回调地址');
+INSERT INTO `sys_config` VALUES (108, '000000', '商户私钥文件路径', 'payment.private.key.path', '', 'N', 103, 1, '2025-12-30 09:44:32', NULL, NULL, '微信支付商户私钥文件路径(apiclient_key.pem)');
+
+SET FOREIGN_KEY_CHECKS = 1;

+ 212 - 0
ruoyi-modules/yp-miniapp/src/main/resources/sql/sys_menu.sql

@@ -0,0 +1,212 @@
+/*
+ Navicat Premium Dump SQL
+
+ Source Server         : zbw
+ Source Server Type    : MySQL
+ Source Server Version : 80042 (8.0.42)
+ Source Host           : localhost:3306
+ Source Schema         : ry_vue_5.x
+
+ Target Server Type    : MySQL
+ Target Server Version : 80042 (8.0.42)
+ File Encoding         : 65001
+
+ Date: 30/12/2025 15:16:37
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for sys_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_menu`;
+CREATE TABLE `sys_menu`  (
+  `menu_id` bigint NOT NULL COMMENT '菜单ID',
+  `menu_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称',
+  `parent_id` bigint NULL DEFAULT 0 COMMENT '父菜单ID',
+  `order_num` int NULL DEFAULT 0 COMMENT '显示顺序',
+  `path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '路由地址',
+  `component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组件路径',
+  `query_param` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路由参数',
+  `is_frame` int NULL DEFAULT 1 COMMENT '是否为外链(0是 1否)',
+  `is_cache` int NULL DEFAULT 0 COMMENT '是否缓存(0缓存 1不缓存)',
+  `menu_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮)',
+  `visible` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '显示状态(0显示 1隐藏)',
+  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '菜单状态(0正常 1停用)',
+  `perms` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '权限标识',
+  `icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '#' COMMENT '菜单图标',
+  `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
+  `create_by` bigint NULL DEFAULT NULL COMMENT '创建者',
+  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+  `update_by` bigint NULL DEFAULT NULL COMMENT '更新者',
+  `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
+  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注',
+  PRIMARY KEY (`menu_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '菜单权限表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sys_menu
+-- ----------------------------
+INSERT INTO `sys_menu` VALUES (1, '系统管理', 0, 1, 'system', NULL, '', 1, 0, 'M', '0', '0', '', 'system', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '系统管理目录');
+INSERT INTO `sys_menu` VALUES (2, '系统监控', 0, 3, 'monitor', NULL, '', 1, 0, 'M', '1', '0', '', 'monitor', 103, 1, '2025-12-19 11:57:50', 1, '2025-12-24 14:54:25', '系统监控目录');
+INSERT INTO `sys_menu` VALUES (3, '系统工具', 0, 4, 'tool', NULL, '', 1, 0, 'M', '1', '0', '', 'tool', 103, 1, '2025-12-19 11:57:50', 1, '2025-12-24 14:54:32', '系统工具目录');
+INSERT INTO `sys_menu` VALUES (4, 'PLUS官网', 0, 5, 'https://gitee.com/dromara/RuoYi-Vue-Plus', NULL, '', 0, 0, 'M', '1', '0', '', 'guide', 103, 1, '2025-12-19 11:57:50', 1, '2025-12-24 14:54:38', 'RuoYi-Vue-Plus官网地址');
+INSERT INTO `sys_menu` VALUES (5, '测试菜单', 0, 5, 'demo', NULL, '', 1, 0, 'M', '1', '0', '', 'star', 103, 1, '2025-12-19 11:57:50', 1, '2025-12-24 14:54:43', '测试菜单');
+INSERT INTO `sys_menu` VALUES (6, '租户管理', 0, 2, 'tenant', NULL, '', 1, 0, 'M', '1', '0', '', 'chart', 103, 1, '2025-12-19 11:57:50', 1, '2025-12-24 14:54:16', '租户管理目录');
+INSERT INTO `sys_menu` VALUES (100, '用户管理', 1, 1, 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '用户管理菜单');
+INSERT INTO `sys_menu` VALUES (101, '角色管理', 1, 2, 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '角色管理菜单');
+INSERT INTO `sys_menu` VALUES (102, '菜单管理', 1, 3, 'menu', 'system/menu/index', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '菜单管理菜单');
+INSERT INTO `sys_menu` VALUES (103, '部门管理', 1, 4, 'dept', 'system/dept/index', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '部门管理菜单');
+INSERT INTO `sys_menu` VALUES (104, '岗位管理', 1, 5, 'post', 'system/post/index', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '岗位管理菜单');
+INSERT INTO `sys_menu` VALUES (105, '字典管理', 1, 6, 'dict', 'system/dict/index', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '字典管理菜单');
+INSERT INTO `sys_menu` VALUES (106, '参数设置', 1, 7, 'config', 'system/config/index', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '参数设置菜单');
+INSERT INTO `sys_menu` VALUES (107, '通知公告', 1, 8, 'notice', 'system/notice/index', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '通知公告菜单');
+INSERT INTO `sys_menu` VALUES (108, '日志管理', 1, 9, 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '日志管理菜单');
+INSERT INTO `sys_menu` VALUES (109, '在线用户', 2, 1, 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '在线用户菜单');
+INSERT INTO `sys_menu` VALUES (113, '缓存监控', 2, 5, 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '缓存监控菜单');
+INSERT INTO `sys_menu` VALUES (115, '代码生成', 3, 2, 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '代码生成菜单');
+INSERT INTO `sys_menu` VALUES (116, '修改生成配置', 3, 2, 'gen-edit/index/:tableId', 'tool/gen/editTable', '', 1, 1, 'C', '1', '0', 'tool:gen:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '/tool/gen');
+INSERT INTO `sys_menu` VALUES (117, 'Admin监控', 2, 5, 'Admin', 'monitor/admin/index', '', 1, 0, 'C', '0', '0', 'monitor:admin:list', 'dashboard', 103, 1, '2025-12-19 11:57:50', NULL, NULL, 'Admin监控菜单');
+INSERT INTO `sys_menu` VALUES (118, '文件管理', 1, 10, 'oss', 'system/oss/index', '', 1, 0, 'C', '0', '0', 'system:oss:list', 'upload', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '文件管理菜单');
+INSERT INTO `sys_menu` VALUES (120, '任务调度中心', 2, 6, 'snailjob', 'monitor/snailjob/index', '', 1, 0, 'C', '0', '0', 'monitor:snailjob:list', 'job', 103, 1, '2025-12-19 11:57:50', NULL, NULL, 'SnailJob控制台菜单');
+INSERT INTO `sys_menu` VALUES (121, '租户管理', 6, 1, 'tenant', 'system/tenant/index', '', 1, 0, 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '租户管理菜单');
+INSERT INTO `sys_menu` VALUES (122, '租户套餐管理', 6, 2, 'tenantPackage', 'system/tenantPackage/index', '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '租户套餐管理菜单');
+INSERT INTO `sys_menu` VALUES (123, '客户端管理', 1, 11, 'client', 'system/client/index', '', 1, 0, 'C', '0', '0', 'system:client:list', 'international', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '客户端管理菜单');
+INSERT INTO `sys_menu` VALUES (130, '分配用户', 1, 2, 'role-auth/user/:roleId', 'system/role/authUser', '', 1, 1, 'C', '1', '0', 'system:role:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '/system/role');
+INSERT INTO `sys_menu` VALUES (131, '分配角色', 1, 1, 'user-auth/role/:userId', 'system/user/authRole', '', 1, 1, 'C', '1', '0', 'system:user:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '/system/user');
+INSERT INTO `sys_menu` VALUES (132, '字典数据', 1, 6, 'dict-data/index/:dictId', 'system/dict/data', '', 1, 1, 'C', '1', '0', 'system:dict:list', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '/system/dict');
+INSERT INTO `sys_menu` VALUES (133, '文件配置管理', 1, 10, 'oss-config/index', 'system/oss/config', '', 1, 1, 'C', '1', '0', 'system:ossConfig:list', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '/system/oss');
+INSERT INTO `sys_menu` VALUES (500, '操作日志', 108, 1, 'operlog', 'monitor/operlog/index', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '操作日志菜单');
+INSERT INTO `sys_menu` VALUES (501, '登录日志', 108, 2, 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '登录日志菜单');
+INSERT INTO `sys_menu` VALUES (1001, '用户查询', 100, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1002, '用户新增', 100, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1003, '用户修改', 100, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1004, '用户删除', 100, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1005, '用户导出', 100, 5, '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1006, '用户导入', 100, 6, '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1007, '重置密码', 100, 7, '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1008, '角色查询', 101, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1009, '角色新增', 101, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1010, '角色修改', 101, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1011, '角色删除', 101, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1012, '角色导出', 101, 5, '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1013, '菜单查询', 102, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1014, '菜单新增', 102, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1015, '菜单修改', 102, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1016, '菜单删除', 102, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1017, '部门查询', 103, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1018, '部门新增', 103, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1019, '部门修改', 103, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1020, '部门删除', 103, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1021, '岗位查询', 104, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1022, '岗位新增', 104, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1023, '岗位修改', 104, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1024, '岗位删除', 104, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1025, '岗位导出', 104, 5, '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1026, '字典查询', 105, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1027, '字典新增', 105, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1028, '字典修改', 105, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1029, '字典删除', 105, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1030, '字典导出', 105, 5, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1031, '参数查询', 106, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1032, '参数新增', 106, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1033, '参数修改', 106, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1034, '参数删除', 106, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1035, '参数导出', 106, 5, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1036, '公告查询', 107, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1037, '公告新增', 107, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1038, '公告修改', 107, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1039, '公告删除', 107, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1040, '操作查询', 500, 1, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1041, '操作删除', 500, 2, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1042, '日志导出', 500, 4, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1043, '登录查询', 501, 1, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1044, '登录删除', 501, 2, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1045, '日志导出', 501, 3, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1046, '在线查询', 109, 1, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1047, '批量强退', 109, 2, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1048, '单条强退', 109, 3, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1050, '账户解锁', 501, 4, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1055, '生成查询', 115, 1, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1056, '生成修改', 115, 2, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1057, '生成删除', 115, 3, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1058, '导入代码', 115, 2, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1059, '预览代码', 115, 4, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1060, '生成代码', 115, 5, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1061, '客户端管理查询', 123, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1062, '客户端管理新增', 123, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1063, '客户端管理修改', 123, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1064, '客户端管理删除', 123, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1065, '客户端管理导出', 123, 5, '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1500, '测试单表', 5, 1, 'demo', 'demo/demo/index', '', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '测试单表菜单');
+INSERT INTO `sys_menu` VALUES (1501, '测试单表查询', 1500, 1, '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1502, '测试单表新增', 1500, 2, '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1503, '测试单表修改', 1500, 3, '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1504, '测试单表删除', 1500, 4, '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1505, '测试单表导出', 1500, 5, '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1506, '测试树表', 5, 1, 'tree', 'demo/tree/index', '', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '测试树表菜单');
+INSERT INTO `sys_menu` VALUES (1507, '测试树表查询', 1506, 1, '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1508, '测试树表新增', 1506, 2, '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1509, '测试树表修改', 1506, 3, '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1510, '测试树表删除', 1506, 4, '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1511, '测试树表导出', 1506, 5, '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1600, '文件查询', 118, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1601, '文件上传', 118, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:upload', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1602, '文件下载', 118, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:download', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1603, '文件删除', 118, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1606, '租户查询', 121, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1607, '租户新增', 121, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1608, '租户修改', 121, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1609, '租户删除', 121, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1610, '租户导出', 121, 5, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1611, '租户套餐查询', 122, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:query', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1612, '租户套餐新增', 122, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1613, '租户套餐修改', 122, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1614, '租户套餐删除', 122, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1615, '租户套餐导出', 122, 5, '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:export', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1620, '配置列表', 118, 5, '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1621, '配置添加', 118, 6, '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1622, '配置编辑', 118, 6, '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (1623, '配置删除', 118, 6, '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, '2025-12-19 11:57:50', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2001, '用户查询', 2003723797282275329, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:user:query', '#', NULL, 1, '2025-12-24 16:14:14', NULL, NULL, '获取小程序用户详细信息');
+INSERT INTO `sys_menu` VALUES (2002, '用户导出', 2003723797282275329, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:user:export', '#', NULL, 1, '2025-12-24 16:14:14', NULL, NULL, '导出小程序用户列表');
+INSERT INTO `sys_menu` VALUES (2003, '用户修改', 2003723797282275329, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:user:edit', '#', NULL, 1, '2025-12-24 16:14:14', NULL, NULL, '修改用户状态和积分');
+INSERT INTO `sys_menu` VALUES (2004, '用户删除', 2003723797282275329, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:user:remove', '#', NULL, 1, '2025-12-29 16:00:00', NULL, NULL, '删除小程序用户');
+INSERT INTO `sys_menu` VALUES (2005310001, '超短池', 2003743180448710658, 2, 'shortPool', 'stock/shortPool/index', '', 1, 0, 'C', '0', '0', 'stock:pool:list', 'monitor', 103, 1, '2025-12-29 00:16:30', 1, '2025-12-29 00:33:08', '超短池菜单');
+INSERT INTO `sys_menu` VALUES (2005310002, '超短池查询', 2005310001, 1, '', '', '', 1, 0, 'F', '0', '0', 'stock:pool:query', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310003, '超短池新增', 2005310001, 2, '', '', '', 1, 0, 'F', '0', '0', 'stock:pool:add', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310004, '超短池删除', 2005310001, 3, '', '', '', 1, 0, 'F', '0', '0', 'stock:pool:remove', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310005, '超短池导出', 2005310001, 4, '', '', '', 1, 0, 'F', '0', '0', 'stock:pool:export', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310006, '强势池', 2003743180448710658, 3, 'strongPool', 'stock/strongPool/index', '', 1, 0, 'C', '0', '0', 'stock:pool:list', 'chart', 103, 1, '2025-12-29 10:31:03', NULL, NULL, '强势池菜单');
+INSERT INTO `sys_menu` VALUES (2005310007, '强势池查询', 2005310006, 1, '', '', '', 1, 0, 'F', '0', '0', 'stock:pool:query', '#', 103, 1, '2025-12-29 10:31:03', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310008, '强势池新增', 2005310006, 2, '', '', '', 1, 0, 'F', '0', '0', 'stock:pool:add', '#', 103, 1, '2025-12-29 10:31:03', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310009, '强势池删除', 2005310006, 3, '', '', '', 1, 0, 'F', '0', '0', 'stock:pool:remove', '#', 103, 1, '2025-12-29 10:31:03', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310010, '股票信息', 2003743180448710658, 1, 'info', 'stock/info/index', '', 1, 0, 'C', '0', '0', 'stock:info:list', 'list', 103, 1, '2025-12-29 00:16:30', 1, '2025-12-29 00:33:41', '股票信息菜单');
+INSERT INTO `sys_menu` VALUES (2005310011, '股票信息查询', 2005310010, 1, '', '', '', 1, 0, 'F', '0', '0', 'stock:info:query', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310012, '股票信息新增', 2005310010, 2, '', '', '', 1, 0, 'F', '0', '0', 'stock:info:add', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310013, '股票信息修改', 2005310010, 3, '', '', '', 1, 0, 'F', '0', '0', 'stock:info:edit', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310014, '股票信息删除', 2005310010, 4, '', '', '', 1, 0, 'F', '0', '0', 'stock:info:remove', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310015, '股票信息导出', 2005310010, 5, '', '', '', 1, 0, 'F', '0', '0', 'stock:info:export', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310016, '股票信息同步', 2005310010, 6, '', '', '', 1, 0, 'F', '0', '0', 'stock:info:sync', '#', 103, 1, '2025-12-29 00:16:30', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310017, '强势池导出', 2005310006, 4, '', '', '', 1, 0, 'F', '0', '0', 'stock:pool:export', '#', 103, 1, '2025-12-29 10:31:03', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310020, '支付配置', 2004074990147751937, 1, 'paymentConfig', NULL, '', 1, 0, 'M', '0', '0', '', 'money', 103, 1, '2025-12-29 17:00:38', NULL, NULL, '支付配置菜单');
+INSERT INTO `sys_menu` VALUES (2005310021, '支付配置查询', 2005310020, 1, '', '', '', 1, 0, 'F', '0', '0', 'miniapp:paymentConfig:query', '#', 103, 1, '2025-12-29 17:00:38', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310022, '支付配置修改', 2005310020, 2, '', '', '', 1, 0, 'F', '0', '0', 'miniapp:paymentConfig:edit', '#', 103, 1, '2025-12-29 17:00:38', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310023, '微信支付配置', 2005310020, 1, 'wxpay', 'settings/paymentConfig/wxpay', '', 1, 0, 'C', '0', '0', 'miniapp:paymentConfig:list', 'wechat', 103, 1, '2025-12-30 09:23:59', NULL, NULL, '微信小程序支付配置');
+INSERT INTO `sys_menu` VALUES (2005310024, '订阅价格配置', 2005310020, 2, 'subscription', 'settings/paymentConfig/subscription', '', 1, 0, 'C', '0', '0', 'miniapp:paymentConfig:list', 'money', 103, 1, '2025-12-30 09:24:11', NULL, NULL, '超短池与强势池订阅价格配置');
+INSERT INTO `sys_menu` VALUES (2005310030, '订阅记录', 2004075918359810049, 1, 'subscription', 'miniapp/subscription/index', '', 1, 0, 'C', '0', '0', 'miniapp:subscription:list', 'list', 103, 1, '2025-12-30 11:45:06', NULL, NULL, '订阅记录菜单');
+INSERT INTO `sys_menu` VALUES (2005310031, '订阅查询', 2005310030, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:subscription:query', '#', 103, 1, '2025-12-30 11:45:06', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310032, '订阅编辑', 2005310030, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:subscription:edit', '#', 103, 1, '2025-12-30 11:45:06', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310033, '订阅删除', 2005310030, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:subscription:remove', '#', 103, 1, '2025-12-30 11:45:06', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310034, '订阅导出', 2005310030, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:subscription:export', '#', 103, 1, '2025-12-30 11:45:06', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310035, '订单记录', 2004075918359810049, 2, 'order', 'miniapp/order/index', '', 1, 0, 'C', '0', '0', 'miniapp:order:list', 'documentation', 103, 1, '2025-12-30 11:45:06', NULL, NULL, '订单记录菜单');
+INSERT INTO `sys_menu` VALUES (2005310036, '订单查询', 2005310035, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:order:query', '#', 103, 1, '2025-12-30 11:45:06', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310037, '订单删除', 2005310035, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:order:remove', '#', 103, 1, '2025-12-30 11:45:06', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2005310038, '订单导出', 2005310035, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'miniapp:order:export', '#', 103, 1, '2025-12-30 11:45:06', NULL, NULL, '');
+INSERT INTO `sys_menu` VALUES (2003723797282275329, '用户管理', 0, 1, 'miniapp/user', 'miniapp/user/index', '', 1, 0, 'C', '0', '0', 'miniapp:user:list', 'peoples', 103, 1, '2025-12-24 15:05:55', 1, '2025-12-29 11:45:11', '');
+INSERT INTO `sys_menu` VALUES (2003743180448710658, '股票管理', 0, 3, 'stock', NULL, NULL, 1, 0, 'M', '0', '0', '', 'chart', 103, 1, '2025-12-24 16:22:57', 1, '2025-12-29 00:32:32', '');
+INSERT INTO `sys_menu` VALUES (2004074990147751937, '配置管理', 0, 4, 'settings', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'example', 103, 1, '2025-12-25 14:21:26', 1, '2025-12-29 11:45:37', '');
+INSERT INTO `sys_menu` VALUES (2004075918359810049, '订阅管理', 0, 2, 'miniapp/order', NULL, NULL, 1, 0, 'M', '0', '0', '', 'shopping', 103, 1, '2025-12-25 14:25:08', 1, '2025-12-29 00:45:16', '');
+
+SET FOREIGN_KEY_CHECKS = 1;

+ 29 - 0
ruoyi-modules/yp-stock/src/main/java/com/yingpai/stock/config/StockThreadPoolConfig.java

@@ -0,0 +1,29 @@
+package com.yingpai.stock.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+public class StockThreadPoolConfig {
+    /**
+     * 股票行情获取专用线程池
+     * 核心线程数:5(控制并发,避免被API限流)
+     * 最大线程数:10
+     * 队列容量:100
+     */
+    @Bean("stockQuoteExecutor")
+    public ThreadPoolTaskExecutor stockQuoteExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setCorePoolSize(5);
+        executor.setMaxPoolSize(10);
+        executor.setQueueCapacity(100);
+        executor.setKeepAliveSeconds(60);
+        executor.setThreadNamePrefix("stock-quote-");
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        executor.initialize();
+        return executor;
+    }
+}

+ 53 - 0
ruoyi-modules/yp-stock/src/main/java/com/yingpai/stock/domain/StockQuoteData.java

@@ -0,0 +1,53 @@
+package com.yingpai.stock.domain;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+
+import java.math.BigDecimal;
+
+/**
+ * 股票实时行情数据
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class StockQuoteData {
+
+    /**
+     * 股票代码
+     */
+    private String stockCode;
+
+    /**
+     * 当前价格
+     */
+    private BigDecimal currentPrice;
+
+    /**
+     * 昨收价
+     */
+    private BigDecimal yesterdayClose;
+
+    /**
+     * 涨跌额
+     */
+    private BigDecimal changeAmount;
+
+    /**
+     * 涨跌幅(%)
+     */
+    private BigDecimal changePercent;
+
+    /**
+     * 换手率(%)
+     */
+    private BigDecimal turnoverRate;
+
+    /**
+     * 成交额(亿)
+     */
+    private BigDecimal tradeAmount;
+}

+ 16 - 0
ruoyi-modules/yp-stock/src/main/java/com/yingpai/stock/service/IStockQuoteService.java

@@ -0,0 +1,16 @@
+package com.yingpai.stock.service;
+
+import com.yingpai.stock.domain.StockQuoteData;
+
+import java.util.List;
+import java.util.Map;
+
+public interface IStockQuoteService {
+    
+    /**
+     * 多线程批量获取实时行情
+     * @param codes 股票代码列表
+     * @return 股票代码 -> 行情数据映射
+     */
+    Map<String, StockQuoteData> batchFetchQuotesParallel(List<String> codes);
+}

+ 16 - 115
ruoyi-modules/yp-stock/src/main/java/com/yingpai/stock/service/impl/StockInfoServiceImpl.java

@@ -5,15 +5,15 @@ import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.yingpai.stock.domain.StockInfo;
 import com.yingpai.stock.domain.StockPool;
+import com.yingpai.stock.domain.StockQuoteData;
 import com.yingpai.stock.domain.bo.StockInfoBo;
 import com.yingpai.stock.domain.vo.StockInfoVo;
 import com.yingpai.stock.mapper.StockInfoMapper;
 import com.yingpai.stock.mapper.StockPoolMapper;
 import com.yingpai.stock.service.IStockInfoService;
+import com.yingpai.stock.service.IStockQuoteService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.utils.StringUtils;
@@ -21,13 +21,6 @@ import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.springframework.stereotype.Service;
 
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.time.Duration;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -42,11 +35,7 @@ public class StockInfoServiceImpl implements IStockInfoService {
 
     private final StockInfoMapper baseMapper;
     private final StockPoolMapper stockPoolMapper;
-    private final ObjectMapper objectMapper = new ObjectMapper();
-
-    private final HttpClient httpClient = HttpClient.newBuilder()
-        .connectTimeout(Duration.ofSeconds(10))
-        .build();
+    private final IStockQuoteService stockQuoteService;
 
     @Override
     public TableDataInfo<StockInfoVo> queryPageList(StockInfoBo bo, PageQuery pageQuery) {
@@ -119,118 +108,30 @@ public class StockInfoServiceImpl implements IStockInfoService {
     }
 
     /**
-     * 填充实时行情数据
+     * 填充实时行情数据(使用多线程服务)
      */
     private void fillRealTimeData(List<StockInfoVo> list) {
         if (list == null || list.isEmpty()) {
             return;
         }
 
-        Map<String, Map<String, Object>> quoteMap = batchFetchQuotes(
-            list.stream().map(StockInfoVo::getStockCode).collect(Collectors.toList())
-        );
+        List<String> codes = list.stream()
+            .map(StockInfoVo::getStockCode)
+            .collect(Collectors.toList());
+
+        // 使用多线程行情服务
+        Map<String, StockQuoteData> quoteMap = stockQuoteService.batchFetchQuotesParallel(codes);
 
         for (StockInfoVo vo : list) {
-            Map<String, Object> quote = quoteMap.get(vo.getStockCode());
+            StockQuoteData quote = quoteMap.get(vo.getStockCode());
             if (quote != null) {
-                vo.setCurrentPrice((BigDecimal) quote.get("currentPrice"));
-                vo.setYesterdayClose((BigDecimal) quote.get("yesterdayClose"));
-                vo.setChangePercent((BigDecimal) quote.get("changePercent"));
-                vo.setTurnoverRate((BigDecimal) quote.get("turnoverRate"));
-                vo.setTradeAmount((BigDecimal) quote.get("tradeAmount"));
-            }
-        }
-    }
-
-    // 东方财富批量行情接口(一次最多50只)
-    private static final String BATCH_QUOTE_URL = "http://push2.eastmoney.com/api/qt/ulist.np/get?fltt=2&fields=f12,f14,f2,f3,f4,f5,f6,f8,f18&secids=%s";
-
-    /**
-     * 批量获取实时行情(使用批量接口,大幅提升速度)
-     */
-    private Map<String, Map<String, Object>> batchFetchQuotes(List<String> codes) {
-        Map<String, Map<String, Object>> result = new HashMap<>();
-        if (codes == null || codes.isEmpty()) {
-            return result;
-        }
-
-        // 每批最多50只股票
-        int batchSize = 50;
-        for (int i = 0; i < codes.size(); i += batchSize) {
-            List<String> batch = codes.subList(i, Math.min(i + batchSize, codes.size()));
-            try {
-                // 构建secids参数
-                String secids = batch.stream()
-                    .map(this::getSecId)
-                    .filter(Objects::nonNull)
-                    .collect(Collectors.joining(","));
-
-                if (secids.isEmpty()) continue;
-
-                String url = String.format(BATCH_QUOTE_URL, secids);
-                HttpRequest request = HttpRequest.newBuilder()
-                    .uri(URI.create(url))
-                    .header("User-Agent", "Mozilla/5.0")
-                    .GET()
-                    .build();
-
-                HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
-
-                if (response.statusCode() == 200) {
-                    JsonNode root = objectMapper.readTree(response.body());
-                    JsonNode data = root.path("data").path("diff");
-
-                    if (data != null && data.isArray()) {
-                        for (JsonNode item : data) {
-                            String code = item.path("f12").asText();
-                            if (code == null || code.isEmpty()) continue;
-
-                            Map<String, Object> quote = new HashMap<>();
-                            // f2=当前价, f3=涨跌幅, f4=涨跌额, f5=成交量, f6=成交额, f8=换手率, f18=昨收
-                            quote.put("currentPrice", parseBigDecimalFromNode(item, "f2"));
-                            quote.put("yesterdayClose", parseBigDecimalFromNode(item, "f18"));
-                            quote.put("changePercent", parseBigDecimalFromNode(item, "f3"));
-                            quote.put("turnoverRate", parseBigDecimalFromNode(item, "f8"));
-
-                            BigDecimal tradeAmount = parseBigDecimalFromNode(item, "f6");
-                            if (tradeAmount != null) {
-                                quote.put("tradeAmount", tradeAmount.divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));
-                            }
-
-                            result.put(code, quote);
-                        }
-                    }
-                }
-
-                // 批次间短暂延迟
-                if (i + batchSize < codes.size()) {
-                    Thread.sleep(100);
-                }
-
-            } catch (Exception e) {
-                log.warn("[批量行情] 获取失败: {}", e.getMessage());
+                vo.setCurrentPrice(quote.getCurrentPrice());
+                vo.setYesterdayClose(quote.getYesterdayClose());
+                vo.setChangePercent(quote.getChangePercent());
+                vo.setTurnoverRate(quote.getTurnoverRate());
+                vo.setTradeAmount(quote.getTradeAmount());
             }
         }
-
-        return result;
-    }
-
-    private BigDecimal parseBigDecimalFromNode(JsonNode node, String field) {
-        if (!node.has(field)) return null;
-        JsonNode value = node.get(field);
-        if (value == null || value.isNull() || "-".equals(value.asText())) return null;
-        try {
-            return new BigDecimal(value.asText());
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-    private String getSecId(String code) {
-        if (code == null || code.length() != 6) return null;
-        if (code.startsWith("6")) return "1." + code;
-        if (code.startsWith("0") || code.startsWith("3")) return "0." + code;
-        return null;
     }
 
     /**

+ 20 - 121
ruoyi-modules/yp-stock/src/main/java/com/yingpai/stock/service/impl/StockPoolServiceImpl.java

@@ -5,13 +5,13 @@ import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.yingpai.stock.domain.StockPool;
+import com.yingpai.stock.domain.StockQuoteData;
 import com.yingpai.stock.domain.bo.StockPoolBo;
 import com.yingpai.stock.domain.vo.StockPoolVo;
 import com.yingpai.stock.mapper.StockPoolMapper;
 import com.yingpai.stock.service.IStockPoolService;
+import com.yingpai.stock.service.IStockQuoteService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.utils.StringUtils;
@@ -22,11 +22,6 @@ import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.*;
@@ -41,11 +36,7 @@ import java.util.stream.Collectors;
 public class StockPoolServiceImpl implements IStockPoolService {
 
     private final StockPoolMapper baseMapper;
-    private final ObjectMapper objectMapper = new ObjectMapper();
-
-    private final HttpClient httpClient = HttpClient.newBuilder()
-        .connectTimeout(Duration.ofSeconds(10))
-        .build();
+    private final IStockQuoteService stockQuoteService;
 
     @Override
     public TableDataInfo<StockPoolVo> queryPageList(StockPoolBo bo, PageQuery pageQuery) {
@@ -183,30 +174,32 @@ public class StockPoolServiceImpl implements IStockPoolService {
     }
 
     /**
-     * 填充实时数据
+     * 填充实时数据(使用多线程服务)
      */
     private void fillRealTimeData(List<StockPoolVo> list) {
         if (list == null || list.isEmpty()) {
             return;
         }
 
-        // 批量获取实时行情
-        Map<String, Map<String, Object>> quoteMap = batchFetchQuotes(
-            list.stream().map(StockPoolVo::getStockCode).collect(Collectors.toList())
-        );
+        List<String> codes = list.stream()
+            .map(StockPoolVo::getStockCode)
+            .collect(Collectors.toList());
+
+        // 使用多线程行情服务
+        Map<String, StockQuoteData> quoteMap = stockQuoteService.batchFetchQuotesParallel(codes);
 
         for (StockPoolVo vo : list) {
             // 设置池类型名称
             vo.setPoolTypeName(vo.getPoolType() == 1 ? "超短池" : "强势池");
 
-            Map<String, Object> quote = quoteMap.get(vo.getStockCode());
+            StockQuoteData quote = quoteMap.get(vo.getStockCode());
             if (quote != null) {
-                vo.setCurrentPrice((BigDecimal) quote.get("currentPrice"));
-                vo.setYesterdayClose((BigDecimal) quote.get("yesterdayClose"));
-                vo.setChangeAmount((BigDecimal) quote.get("changeAmount"));
-                vo.setChangePercent((BigDecimal) quote.get("changePercent"));
-                vo.setTurnoverRate((BigDecimal) quote.get("turnoverRate"));
-                vo.setTradeAmount((BigDecimal) quote.get("tradeAmount"));
+                vo.setCurrentPrice(quote.getCurrentPrice());
+                vo.setYesterdayClose(quote.getYesterdayClose());
+                vo.setChangeAmount(quote.getChangeAmount());
+                vo.setChangePercent(quote.getChangePercent());
+                vo.setTurnoverRate(quote.getTurnoverRate());
+                vo.setTradeAmount(quote.getTradeAmount());
 
                 // 计算入池收益率
                 if (vo.getAddPrice() != null && vo.getCurrentPrice() != null
@@ -220,106 +213,12 @@ public class StockPoolServiceImpl implements IStockPoolService {
         }
     }
 
-    // 东方财富批量行情接口(一次最多50只)
-    private static final String BATCH_QUOTE_URL = "http://push2.eastmoney.com/api/qt/ulist.np/get?fltt=2&fields=f12,f14,f2,f3,f4,f5,f6,f8,f18&secids=%s";
-
-    /**
-     * 批量获取实时行情(使用批量接口)
-     */
-    private Map<String, Map<String, Object>> batchFetchQuotes(List<String> codes) {
-        Map<String, Map<String, Object>> result = new HashMap<>();
-        if (codes == null || codes.isEmpty()) {
-            return result;
-        }
-
-        // 每批最多50只股票
-        int batchSize = 50;
-        for (int i = 0; i < codes.size(); i += batchSize) {
-            List<String> batch = codes.subList(i, Math.min(i + batchSize, codes.size()));
-            try {
-                String secids = batch.stream()
-                    .map(this::getSecId)
-                    .filter(Objects::nonNull)
-                    .collect(Collectors.joining(","));
-
-                if (secids.isEmpty()) continue;
-
-                String url = String.format(BATCH_QUOTE_URL, secids);
-                HttpRequest request = HttpRequest.newBuilder()
-                    .uri(URI.create(url))
-                    .header("User-Agent", "Mozilla/5.0")
-                    .GET()
-                    .build();
-
-                HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
-
-                if (response.statusCode() == 200) {
-                    JsonNode root = objectMapper.readTree(response.body());
-                    JsonNode data = root.path("data").path("diff");
-
-                    if (data != null && data.isArray()) {
-                        for (JsonNode item : data) {
-                            String code = item.path("f12").asText();
-                            if (code == null || code.isEmpty()) continue;
-
-                            Map<String, Object> quote = new HashMap<>();
-                            quote.put("currentPrice", parseBigDecimal(item, "f2"));
-                            quote.put("yesterdayClose", parseBigDecimal(item, "f18"));
-                            quote.put("changePercent", parseBigDecimal(item, "f3"));
-                            quote.put("turnoverRate", parseBigDecimal(item, "f8"));
-
-                            BigDecimal tradeAmount = parseBigDecimal(item, "f6");
-                            if (tradeAmount != null) {
-                                quote.put("tradeAmount", tradeAmount.divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));
-                            }
-
-                            result.put(code, quote);
-                        }
-                    }
-                }
-
-                if (i + batchSize < codes.size()) {
-                    Thread.sleep(100);
-                }
-
-            } catch (Exception e) {
-                log.warn("[批量行情] 获取失败: {}", e.getMessage());
-            }
-        }
-
-        return result;
-    }
-
     /**
      * 获取单个股票当前价格
      */
     private BigDecimal fetchCurrentPrice(String code) {
-        Map<String, Map<String, Object>> quotes = batchFetchQuotes(List.of(code));
-        Map<String, Object> quote = quotes.get(code);
-        return quote != null ? (BigDecimal) quote.get("currentPrice") : null;
-    }
-
-    /**
-     * 获取secId
-     */
-    private String getSecId(String code) {
-        if (code == null || code.length() != 6) return null;
-        if (code.startsWith("6")) return "1." + code;
-        if (code.startsWith("0") || code.startsWith("3")) return "0." + code;
-        return null;
-    }
-
-    /**
-     * 解析BigDecimal
-     */
-    private BigDecimal parseBigDecimal(JsonNode node, String field) {
-        if (!node.has(field)) return null;
-        JsonNode value = node.get(field);
-        if (value == null || value.isNull() || "-".equals(value.asText())) return null;
-        try {
-            return new BigDecimal(value.asText());
-        } catch (Exception e) {
-            return null;
-        }
+        Map<String, StockQuoteData> quotes = stockQuoteService.batchFetchQuotesParallel(List.of(code));
+        StockQuoteData quote = quotes.get(code);
+        return quote != null ? quote.getCurrentPrice() : null;
     }
 }

+ 179 - 0
ruoyi-modules/yp-stock/src/main/java/com/yingpai/stock/service/impl/StockQuoteServiceImpl.java

@@ -0,0 +1,179 @@
+package com.yingpai.stock.service.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.yingpai.stock.domain.StockQuoteData;
+import com.yingpai.stock.service.IStockQuoteService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ * 股票行情服务实现类(多线程优化)
+ */
+@Slf4j
+@Service
+public class StockQuoteServiceImpl implements IStockQuoteService {
+
+    private final ThreadPoolTaskExecutor executor;
+    private final ObjectMapper objectMapper = new ObjectMapper();
+
+    private final HttpClient httpClient = HttpClient.newBuilder()
+        .connectTimeout(Duration.ofSeconds(10))
+        .build();
+
+    private static final int BATCH_SIZE = 50;
+    private static final String BATCH_QUOTE_URL = "http://push2.eastmoney.com/api/qt/ulist.np/get?fltt=2&fields=f12,f14,f2,f3,f4,f5,f6,f8,f18&secids=%s";
+
+    public StockQuoteServiceImpl(@Qualifier("stockQuoteExecutor") ThreadPoolTaskExecutor executor) {
+        this.executor = executor;
+    }
+
+    @Override
+    public Map<String, StockQuoteData> batchFetchQuotesParallel(List<String> codes) {
+        if (codes == null || codes.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        long startTime = System.currentTimeMillis();
+        log.info("[行情获取] 开始多线程获取,股票数量: {}", codes.size());
+
+        // 1. 数据分片
+        List<List<String>> batches = partition(codes, BATCH_SIZE);
+        log.info("[行情获取] 分为 {} 个批次", batches.size());
+
+        // 2. 并行请求
+        List<CompletableFuture<Map<String, StockQuoteData>>> futures = new ArrayList<>();
+        for (List<String> batch : batches) {
+            CompletableFuture<Map<String, StockQuoteData>> future = CompletableFuture.supplyAsync(
+                () -> fetchBatchQuotes(batch),
+                executor
+            );
+            futures.add(future);
+        }
+
+        // 3. 等待所有任务完成并合并结果
+        Map<String, StockQuoteData> result = new ConcurrentHashMap<>();
+
+        try {
+            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
+
+            for (CompletableFuture<Map<String, StockQuoteData>> future : futures) {
+                try {
+                    result.putAll(future.get());
+                } catch (Exception e) {
+                    log.warn("[行情获取] 部分批次失败: {}", e.getMessage());
+                }
+            }
+        } catch (Exception e) {
+            log.error("[行情获取] 多线程执行异常: {}", e.getMessage());
+        }
+
+        long costTime = System.currentTimeMillis() - startTime;
+        log.info("[行情获取] 完成,获取到 {} 条数据,耗时 {}ms", result.size(), costTime);
+
+        return result;
+    }
+
+    /**
+     * 获取单批次行情(最多50只股票)
+     */
+    private Map<String, StockQuoteData> fetchBatchQuotes(List<String> batch) {
+        Map<String, StockQuoteData> result = new HashMap<>();
+        try {
+            String secids = batch.stream()
+                .map(this::getSecId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.joining(","));
+
+            if (secids.isEmpty()) return result;
+
+            HttpRequest request = HttpRequest.newBuilder()
+                .uri(URI.create(String.format(BATCH_QUOTE_URL, secids)))
+                .header("User-Agent", "Mozilla/5.0")
+                .GET()
+                .build();
+
+            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+
+            if (response.statusCode() == 200) {
+                JsonNode root = objectMapper.readTree(response.body());
+                JsonNode data = root.path("data").path("diff");
+
+                if (data != null && data.isArray()) {
+                    for (JsonNode item : data) {
+                        String code = item.path("f12").asText();
+                        if (code == null || code.isEmpty()) continue;
+
+                        StockQuoteData quote = StockQuoteData.builder()
+                            .stockCode(code)
+                            .currentPrice(parseBigDecimal(item, "f2"))
+                            .yesterdayClose(parseBigDecimal(item, "f18"))
+                            .changeAmount(parseBigDecimal(item, "f4"))
+                            .changePercent(parseBigDecimal(item, "f3"))
+                            .turnoverRate(parseBigDecimal(item, "f8"))
+                            .build();
+
+                        BigDecimal tradeAmount = parseBigDecimal(item, "f6");
+                        if (tradeAmount != null) {
+                            quote.setTradeAmount(tradeAmount.divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));
+                        }
+
+                        result.put(code, quote);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.warn("[批量行情] 获取失败: {}", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 数据分片
+     */
+    private <T> List<List<T>> partition(List<T> list, int size) {
+        List<List<T>> partitions = new ArrayList<>();
+        for (int i = 0; i < list.size(); i += size) {
+            partitions.add(new ArrayList<>(list.subList(i, Math.min(i + size, list.size()))));
+        }
+        return partitions;
+    }
+
+    /**
+     * 获取secId(东方财富格式)
+     */
+    private String getSecId(String code) {
+        if (code == null || code.length() != 6) return null;
+        if (code.startsWith("6")) return "1." + code;
+        if (code.startsWith("0") || code.startsWith("3")) return "0." + code;
+        return null;
+    }
+
+    /**
+     * 解析BigDecimal
+     */
+    private BigDecimal parseBigDecimal(JsonNode node, String field) {
+        if (!node.has(field)) return null;
+        JsonNode value = node.get(field);
+        if (value == null || value.isNull() || "-".equals(value.asText())) return null;
+        try {
+            return new BigDecimal(value.asText());
+        } catch (Exception e) {
+            return null;
+        }
+    }
+}