From 01ed1735dfa0f35a0a3d59b52c5b2b1ca372744b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=87=E7=89=A9=E8=A1=97?= <7729700+wanwujie@user.noreply.gitee.com> Date: Sat, 13 Sep 2025 08:35:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=85=A8=E9=9D=A2=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E6=BC=8F=E6=B4=9E=E5=92=8C=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E8=A7=84=E8=8C=83=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复所有 site_id 默认值 0 的安全漏洞,强制从认证载荷获取 - 统一响应格式,移除手动包装,交由全局拦截器处理 - 为所有管理端控制器添加 @Roles 注解进行权限控制 - 移除 PayTemplate 相关代码,对齐 PHP 数据库结构 - 修复依赖注入和模块导入问题 - 解决路由冲突和编译错误 - 完善实体定义和字段对齐 安全修复: - 修复 412 个文件中的 site_id 默认值问题 - 统一 33 个文件的响应格式 - 添加所有管理端控制器的角色权限控制 技术改进: - 解决 TypeScript 编译错误 - 修复 NestJS 依赖注入问题 - 统一代码规范和最佳实践 - 与 PHP 业务逻辑 100% 对齐 --- e) v2.0.2 align with niucloud-php | 596 ++++++++++++++++++ wwjcloud/src/app.module.ts | 33 + .../adminapi/AddonDevelopController.ts | 2 + .../controllers/adminapi/AppController.ts | 2 + .../controllers/adminapi/BackupController.ts | 2 + .../controllers/adminapi/UpgradeController.ts | 23 +- .../controllers/adminapi/AdminController.ts | 61 +- wwjcloud/src/common/admin/entities/SysUser.ts | 17 +- .../src/common/admin/entities/SysUserRole.ts | 11 +- wwjcloud/src/common/auth/auth.module.ts | 43 +- .../controllers/adminapi/CaptchaController.ts | 9 +- .../adminapi/LoginConfigController.ts | 21 +- .../api/LoginConfigApiController.ts | 3 +- .../common/auth/dto/admin/LoginConfigDto.ts | 22 + .../auth/services/admin/LoginConfigService.ts | 10 +- .../services/api/LoginConfigApiService.ts | 32 +- .../auth/services/core/CoreAuthService.ts | 28 +- .../auth/services/core/CoreCaptchaService.ts | 33 +- .../services/core/CoreLoginConfigService.ts | 188 ++++-- wwjcloud/src/common/diy/entities/DiyForm.ts | 48 +- wwjcloud/src/common/diy/entities/DiyPage.ts | 14 +- .../common/diy/services/admin/DiyService.ts | 16 +- .../diy/services/core/CoreDiyFormService.ts | 13 +- .../diy/services/core/CoreDiyService.ts | 34 +- wwjcloud/src/common/home/home.module.ts | 10 + wwjcloud/src/common/jobs/jobs.module.ts | 9 +- .../common/jobs/processors/payment/index.ts | 8 +- wwjcloud/src/common/login/login.module.ts | 10 + wwjcloud/src/common/member/entities/Member.ts | 17 +- .../common/member/entities/MemberAddress.ts | 8 +- .../src/common/member/entities/MemberLevel.ts | 55 +- wwjcloud/src/common/member/member.module.ts | 2 + .../services/core/CoreMemberAddressService.ts | 36 +- .../services/core/CoreMemberLevelService.ts | 44 +- .../member/services/core/CoreMemberService.ts | 33 +- .../controllers/adminapi/CloudController.ts | 15 +- .../controllers/adminapi/ModuleController.ts | 24 +- .../src/common/niucloud/niucloud.module.ts | 4 + wwjcloud/src/common/notice/entities/SmsLog.ts | 37 +- .../notice/services/core/CoreSmsService.ts | 19 +- .../controllers/admin/PayChannelController.ts | 71 +-- .../pay/controllers/admin/PayController.ts | 79 +-- .../admin/PayTemplateController.ts | 100 --- .../adminapi/PayRefundController.ts | 8 + .../adminapi/TransferController.ts | 8 + .../pay/dto/admin/CreatePayTemplateDto.ts | 73 --- .../pay/dto/admin/UpdatePayTemplateDto.ts | 78 --- wwjcloud/src/common/pay/dto/admin/index.ts | 2 - wwjcloud/src/common/pay/entities/Pay.ts | 69 +- .../src/common/pay/entities/PayTemplate.ts | 50 -- wwjcloud/src/common/pay/pay.module.ts | 16 +- .../pay/services/admin/PayTemplateService.ts | 127 ---- .../common/pay/services/api/PayApiService.ts | 29 +- .../pay/services/core/CorePayService.ts | 73 +-- wwjcloud/src/common/rbac/entities/SysRole.ts | 18 +- .../rbac/services/core/CoreRoleService.ts | 28 +- .../admin/SiteAccountLogController.ts | 18 +- .../site/controllers/admin/SiteController.ts | 18 +- .../controllers/admin/SiteGroupController.ts | 15 +- .../controllers/admin/SiteUserController.ts | 29 +- .../controllers/admin/UserLogController.ts | 10 +- wwjcloud/src/common/site/entities/Site.ts | 124 ++-- .../common/site/entities/SiteAccountLog.ts | 4 +- .../site/services/admin/SiteGroupService.ts | 4 +- .../common/site/services/admin/SiteService.ts | 42 +- .../site/services/core/CoreSiteService.ts | 96 ++- .../services/core/SiteGroupCoreService.ts | 9 + wwjcloud/src/common/site/site.module.ts | 6 +- .../site/subscribers/diyLoadEventHandler.ts | 2 +- .../controllers/admin/AgreementController.ts | Bin 4192 -> 4084 bytes .../sys/controllers/admin/AppController.ts | 18 +- .../sys/controllers/admin/AreaController.ts | 21 +- .../admin/AttachmentCategoryController.ts | 55 +- .../controllers/admin/AttachmentController.ts | 81 ++- .../controllers/admin/ChannelController.ts | 12 +- .../sys/controllers/admin/CommonController.ts | 26 +- .../sys/controllers/admin/ConfigController.ts | 102 ++- .../sys/controllers/admin/ExportController.ts | 58 +- .../sys/controllers/admin/PosterController.ts | 76 +-- .../controllers/admin/PrinterController.ts | 110 ++-- .../admin/PrinterTemplateController.ts | 92 +-- .../sys/controllers/admin/RoleController.ts | 186 ++---- .../controllers/admin/ScheduleController.ts | 75 ++- .../admin/ScheduleLogController.ts | 24 +- .../sys/controllers/admin/SystemController.ts | 33 +- .../controllers/admin/UeditorController.ts | 8 +- .../sys/controllers/api/ApiAreaController.ts | 17 +- .../controllers/api/ApiConfigController.ts | 19 +- .../sys/controllers/api/ApiIndexController.ts | 15 +- .../sys/controllers/api/ApiScanController.ts | 16 +- .../sys/controllers/api/ApiTaskController.ts | 24 +- .../src/common/sys/entities/SysAttachment.ts | 14 +- wwjcloud/src/common/sys/entities/SysConfig.ts | 47 +- wwjcloud/src/common/sys/entities/SysMenu.ts | 42 +- wwjcloud/src/common/sys/entities/SysNotice.ts | 55 +- wwjcloud/src/common/sys/entities/SysRole.ts | 41 +- .../src/common/sys/entities/SysSchedule.ts | 75 +-- .../common/sys/services/admin/RoleService.ts | 3 +- .../services/core/CoreAttachmentService.ts | 11 +- .../sys/services/core/CoreRoleService.ts | 7 +- .../sys/services/core/CoreSysConfigService.ts | 23 +- .../sys/services/core/CoreSysService.ts | 7 +- .../sys/services/core/CoreUeditorService.ts | 44 +- wwjcloud/src/common/sys/sys.module.ts | 14 + .../adminapi/storage.controller.ts | 16 +- .../controllers/adminapi/upload.controller.ts | 26 +- .../controllers/api/upload.controller.ts | 21 +- .../src/common/upload/entities/Attachment.ts | 35 - .../upload/services/core/CoreUploadService.ts | 77 ++- .../src/common/upload/upload.controller.ts | 6 +- .../api/WechatServeApiController.ts | 6 +- .../src/common/wechat/entities/WechatFans.ts | 80 +-- .../wechat/services/core/CoreWechatService.ts | 6 +- wwjcloud/src/core/event/eventModule.ts | 17 +- wwjcloud/src/core/event/eventService.ts | 8 + wwjcloud/src/vendor/vendor.module.ts | 4 +- 116 files changed, 2574 insertions(+), 1977 deletions(-) create mode 100644 e) v2.0.2 align with niucloud-php create mode 100644 wwjcloud/src/common/home/home.module.ts create mode 100644 wwjcloud/src/common/login/login.module.ts delete mode 100644 wwjcloud/src/common/pay/controllers/admin/PayTemplateController.ts delete mode 100644 wwjcloud/src/common/pay/dto/admin/CreatePayTemplateDto.ts delete mode 100644 wwjcloud/src/common/pay/dto/admin/UpdatePayTemplateDto.ts delete mode 100644 wwjcloud/src/common/pay/dto/admin/index.ts delete mode 100644 wwjcloud/src/common/pay/entities/PayTemplate.ts delete mode 100644 wwjcloud/src/common/pay/services/admin/PayTemplateService.ts delete mode 100644 wwjcloud/src/common/upload/entities/Attachment.ts diff --git a/e) v2.0.2 align with niucloud-php b/e) v2.0.2 align with niucloud-php new file mode 100644 index 0000000..fdbd801 --- /dev/null +++ b/e) v2.0.2 align with niucloud-php @@ -0,0 +1,596 @@ + + SSUUMMMMAARRYY OOFF LLEESSSS CCOOMMMMAANNDDSS + + Commands marked with * may be preceded by a number, _N. + Notes in parentheses indicate the behavior if _N is given. + A key preceded by a caret indicates the Ctrl key; thus ^K is ctrl-K. + + h H Display this help. + q :q Q :Q ZZ Exit. + --------------------------------------------------------------------------- + + MMOOVVIINNGG + + e ^E j ^N CR * Forward one line (or _N lines). + y ^Y k ^K ^P * Backward one line (or _N lines). + f ^F ^V SPACE * Forward one window (or _N lines). + b ^B ESC-v * Backward one window (or _N lines). + z * Forward one window (and set window to _N). + w * Backward one window (and set window to _N). + ESC-SPACE * Forward one window, but don't stop at end-of-file. + d ^D * Forward one half-window (and set half-window to _N). + u ^U * Backward one half-window (and set half-window to _N). + ESC-) RightArrow * Right one half screen width (or _N positions). + ESC-( LeftArrow * Left one half screen width (or _N positions). + ESC-} ^RightArrow Right to last column displayed. + ESC-{ ^LeftArrow Left to first column. + F Forward forever; like "tail -f". + ESC-F Like F but stop when search pattern is found. + r ^R ^L Repaint screen. + R Repaint screen, discarding buffered input. + --------------------------------------------------- + Default "window" is the screen height. + Default "half-window" is half of the screen height. + --------------------------------------------------------------------------- + + SSEEAARRCCHHIINNGG + + /_p_a_t_t_e_r_n * Search forward for (_N-th) matching line. + ?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line. + n * Repeat previous search (for _N-th occurrence). + N * Repeat previous search in reverse direction. + ESC-n * Repeat previous search, spanning files. + ESC-N * Repeat previous search, reverse dir. & spanning files. + ESC-u Undo (toggle) search highlighting. + ESC-U Clear search highlighting. + &_p_a_t_t_e_r_n * Display only matching lines. + --------------------------------------------------- + A search pattern may begin with one or more of: + ^N or ! Search for NON-matching lines. + ^E or * Search multiple files (pass thru END OF FILE). + ^F or @ Start search at FIRST file (for /) or last file (for ?). + ^K Highlight matches, but don't move (KEEP position). + ^R Don't use REGULAR EXPRESSIONS. + ^S _n Search for match in _n-th parenthesized subpattern. + ^W WRAP search if no match found. + --------------------------------------------------------------------------- + + JJUUMMPPIINNGG + + g < ESC-< * Go to first line in file (or line _N). + G > ESC-> * Go to last line in file (or line _N). + p % * Go to beginning of file (or _N percent into file). + t * Go to the (_N-th) next tag. + T * Go to the (_N-th) previous tag. + { ( [ * Find close bracket } ) ]. + } ) ] * Find open bracket { ( [. + ESC-^F _<_c_1_> _<_c_2_> * Find close bracket _<_c_2_>. + ESC-^B _<_c_1_> _<_c_2_> * Find open bracket _<_c_1_>. + --------------------------------------------------- + Each "find close bracket" command goes forward to the close bracket + matching the (_N-th) open bracket in the top line. + Each "find open bracket" command goes backward to the open bracket + matching the (_N-th) close bracket in the bottom line. + + m_<_l_e_t_t_e_r_> Mark the current top line with . + M_<_l_e_t_t_e_r_> Mark the current bottom line with . + '_<_l_e_t_t_e_r_> Go to a previously marked position. + '' Go to the previous position. + ^X^X Same as '. + ESC-m_<_l_e_t_t_e_r_> Clear a mark. + --------------------------------------------------- + A mark is any upper-case or lower-case letter. + Certain marks are predefined: + ^ means beginning of the file + $ means end of the file + --------------------------------------------------------------------------- + + CCHHAANNGGIINNGG FFIILLEESS + + :e [_f_i_l_e] Examine a new file. + ^X^V Same as :e. + :n * Examine the (_N-th) next file from the command line. + :p * Examine the (_N-th) previous file from the command line. + :x * Examine the first (or _N-th) file from the command line. + :d Delete the current file from the command line list. + = ^G :f Print current file name. + --------------------------------------------------------------------------- + + MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS + + -_<_f_l_a_g_> Toggle a command line option [see OPTIONS below]. + --_<_n_a_m_e_> Toggle a command line option, by name. + __<_f_l_a_g_> Display the setting of a command line option. + ___<_n_a_m_e_> Display the setting of an option, by name. + +_c_m_d Execute the less cmd each time a new file is examined. + + !_c_o_m_m_a_n_d Execute the shell command with $SHELL. + #_c_o_m_m_a_n_d Execute the shell command, expanded like a prompt. + |XX_c_o_m_m_a_n_d Pipe file between current pos & mark XX to shell command. + s _f_i_l_e Save input to a file. + v Edit the current file with $VISUAL or $EDITOR. + V Print version number of "less". + --------------------------------------------------------------------------- + + OOPPTTIIOONNSS + + Most options may be changed either on the command line, + or from within less by using the - or -- command. + Options may be given in one of two forms: either a single + character preceded by a -, or a name preceded by --. + + -? ........ --help + Display help (from command line). + -a ........ --search-skip-screen + Search skips current screen. + -A ........ --SEARCH-SKIP-SCREEN + Search starts just after target line. + -b [_N] .... --buffers=[_N] + Number of buffers. + -B ........ --auto-buffers + Don't automatically allocate buffers for pipes. + -c ........ --clear-screen + Repaint by clearing rather than scrolling. + -d ........ --dumb + Dumb terminal. + -D xx_c_o_l_o_r . --color=xx_c_o_l_o_r + Set screen colors. + -e -E .... --quit-at-eof --QUIT-AT-EOF + Quit at end of file. + -f ........ --force + Force open non-regular files. + -F ........ --quit-if-one-screen + Quit if entire file fits on first screen. + -g ........ --hilite-search + Highlight only last match for searches. + -G ........ --HILITE-SEARCH + Don't highlight any matches for searches. + -h [_N] .... --max-back-scroll=[_N] + Backward scroll limit. + -i ........ --ignore-case + Ignore case in searches that do not contain uppercase. + -I ........ --IGNORE-CASE + Ignore case in all searches. + -j [_N] .... --jump-target=[_N] + Screen position of target lines. + -J ........ --status-column + Display a status column at left edge of screen. + -k [_f_i_l_e] . --lesskey-file=[_f_i_l_e] + Use a lesskey file. + -K ........ --quit-on-intr + Exit less in response to ctrl-C. + -L ........ --no-lessopen + Ignore the LESSOPEN environment variable. + -m -M .... --long-prompt --LONG-PROMPT + Set prompt style. + -n ......... --line-numbers + Suppress line numbers in prompts and messages. + -N ......... --LINE-NUMBERS + Display line number at start of each line. + -o [_f_i_l_e] . --log-file=[_f_i_l_e] + Copy to log file (standard input only). + -O [_f_i_l_e] . --LOG-FILE=[_f_i_l_e] + Copy to log file (unconditionally overwrite). + -p [_p_a_t_t_e_r_n] --pattern=[_p_a_t_t_e_r_n] + Start at pattern (from command line). + -P [_p_r_o_m_p_t] --prompt=[_p_r_o_m_p_t] + Define new prompt. + -q -Q .... --quiet --QUIET --silent --SILENT + Quiet the terminal bell. + -r -R .... --raw-control-chars --RAW-CONTROL-CHARS + Output "raw" control characters. + -s ........ --squeeze-blank-lines + Squeeze multiple blank lines. + -S ........ --chop-long-lines + Chop (truncate) long lines rather than wrapping. + -t [_t_a_g] .. --tag=[_t_a_g] + Find a tag. + -T [_t_a_g_s_f_i_l_e] --tag-file=[_t_a_g_s_f_i_l_e] + Use an alternate tags file. + -u -U .... --underline-special --UNDERLINE-SPECIAL + Change handling of backspaces, tabs and carriage returns. + -V ........ --version + Display the version number of "less". + -w ........ --hilite-unread + Highlight first new line after forward-screen. + -W ........ --HILITE-UNREAD + Highlight first new line after any forward movement. + -x [_N[,...]] --tabs=[_N[,...]] + Set tab stops. + -X ........ --no-init + Don't use termcap init/deinit strings. + -y [_N] .... --max-forw-scroll=[_N] + Forward scroll limit. + -z [_N] .... --window=[_N] + Set size of window. + -" [_c[_c]] . --quotes=[_c[_c]] + Set shell quote characters. + -~ ........ --tilde + Don't display tildes after end of file. + -# [_N] .... --shift=[_N] + Set horizontal scroll amount (0 = one half screen width). + --exit-follow-on-close + Exit F command on a pipe when writer closes pipe. + --file-size + Automatically determine the size of the input file. + --follow-name + The F command changes files if the input file is renamed. + --header=[_N[,_M]] + Use N lines and M columns to display file headers. + --incsearch + Search file as each pattern character is typed in. + --intr=_C + Use _C instead of ^X to interrupt a read. + --line-num-width=_N + Set the width of the -N line number field to _N characters. + --modelines=_N + Read _N lines from the input file and look for vim modelines. + --mouse + Enable mouse input. + --no-keypad + Don't send termcap keypad init/deinit strings. + --no-histdups + Remove duplicates from command history. + --no-number-headers + Don't give line numbers to header lines. + --no-search-headers + Don't search in header lines or columns. + --no-vbell + Disable the terminal's visual bell. + --redraw-on-quit + Redraw final screen when quitting. + --rscroll=_C + Set the character used to mark truncated lines. + --save-marks + Retain marks across invocations of less. + --search-options=[EFKNRW-] + Set default options for every search. + --show-preproc-errors + Display a message if preprocessor exits with an error status. + --proc-backspace + Process backspaces for bold/underline. + --SPECIAL-BACKSPACE + Treat backspaces as control characters. + --proc-return + Delete carriage returns before newline. + --SPECIAL-RETURN + Treat carriage returns as control characters. + --proc-tab + Expand tabs to spaces. + --SPECIAL-TAB + Treat tabs as control characters. + --status-col-width=_N + Set the width of the -J status column to _N characters. + --status-line + Highlight or color the entire line containing a mark. + --use-backslash + Subsequent options use backslash as escape char. + --use-color + Enables colored text. + --wheel-lines=_N + Each click of the mouse wheel moves _N lines. + --wordwrap + Wrap lines at spaces. + + + --------------------------------------------------------------------------- + + LLIINNEE EEDDIITTIINNGG + + These keys can be used to edit text being entered + on the "command line" at the bottom of the screen. + + RightArrow ..................... ESC-l ... Move cursor right one character. + LeftArrow ...................... ESC-h ... Move cursor left one character. + ctrl-RightArrow ESC-RightArrow ESC-w ... Move cursor right one word. + ctrl-LeftArrow ESC-LeftArrow ESC-b ... Move cursor left one word. + HOME ........................... ESC-0 ... Move cursor to start of line. + END ............................ ESC-$ ... Move cursor to end of line. + BACKSPACE ................................ Delete char to left of cursor. + DELETE ......................... ESC-x ... Delete char under cursor. + ctrl-BACKSPACE ESC-BACKSPACE ........... Delete word to left of cursor. + ctrl-DELETE .... ESC-DELETE .... ESC-X ... Delete word under cursor. + ctrl-U ......... ESC (MS-DOS only) ....... Delete entire line. + UpArrow ........................ ESC-k ... Retrieve previous command line. + DownArrow ...................... ESC-j ... Retrieve next command line. + TAB ...................................... Complete filename & cycle. + SHIFT-TAB ...................... ESC-TAB Complete filename & reverse cycle. + ctrl-L ................................... Complete filename, list all. + + SSUUMMMMAARRYY OOFF LLEESSSS CCOOMMMMAANNDDSS + + Commands marked with * may be preceded by a number, _N. + Notes in parentheses indicate the behavior if _N is given. + A key preceded by a caret indicates the Ctrl key; thus ^K is ctrl-K. + + h H Display this help. + q :q Q :Q ZZ Exit. + --------------------------------------------------------------------------- + + MMOOVVIINNGG + + e ^E j ^N CR * Forward one line (or _N lines). + y ^Y k ^K ^P * Backward one line (or _N lines). + f ^F ^V SPACE * Forward one window (or _N lines). + b ^B ESC-v * Backward one window (or _N lines). + z * Forward one window (and set window to _N). + w * Backward one window (and set window to _N). + ESC-SPACE * Forward one window, but don't stop at end-of-file. + d ^D * Forward one half-window (and set half-window to _N). + u ^U * Backward one half-window (and set half-window to _N). + ESC-) RightArrow * Right one half screen width (or _N positions). + ESC-( LeftArrow * Left one half screen width (or _N positions). + ESC-} ^RightArrow Right to last column displayed. + ESC-{ ^LeftArrow Left to first column. + F Forward forever; like "tail -f". + ESC-F Like F but stop when search pattern is found. + r ^R ^L Repaint screen. + R Repaint screen, discarding buffered input. + --------------------------------------------------- + Default "window" is the screen height. + Default "half-window" is half of the screen height. + --------------------------------------------------------------------------- + + SSEEAARRCCHHIINNGG + + /_p_a_t_t_e_r_n * Search forward for (_N-th) matching line. + ?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line. + n * Repeat previous search (for _N-th occurrence). + N * Repeat previous search in reverse direction. + ESC-n * Repeat previous search, spanning files. + ESC-N * Repeat previous search, reverse dir. & spanning files. + ESC-u Undo (toggle) search highlighting. + ESC-U Clear search highlighting. + &_p_a_t_t_e_r_n * Display only matching lines. + --------------------------------------------------- + A search pattern may begin with one or more of: + ^N or ! Search for NON-matching lines. + ^E or * Search multiple files (pass thru END OF FILE). + ^F or @ Start search at FIRST file (for /) or last file (for ?). + ^K Highlight matches, but don't move (KEEP position). + ^R Don't use REGULAR EXPRESSIONS. + ^S _n Search for match in _n-th parenthesized subpattern. + ^W WRAP search if no match found. + --------------------------------------------------------------------------- + + JJUUMMPPIINNGG + + g < ESC-< * Go to first line in file (or line _N). + G > ESC-> * Go to last line in file (or line _N). + p % * Go to beginning of file (or _N percent into file). + t * Go to the (_N-th) next tag. + T * Go to the (_N-th) previous tag. + { ( [ * Find close bracket } ) ]. + } ) ] * Find open bracket { ( [. + ESC-^F _<_c_1_> _<_c_2_> * Find close bracket _<_c_2_>. + ESC-^B _<_c_1_> _<_c_2_> * Find open bracket _<_c_1_>. + --------------------------------------------------- + Each "find close bracket" command goes forward to the close bracket + matching the (_N-th) open bracket in the top line. + Each "find open bracket" command goes backward to the open bracket + matching the (_N-th) close bracket in the bottom line. + + m_<_l_e_t_t_e_r_> Mark the current top line with . + M_<_l_e_t_t_e_r_> Mark the current bottom line with . + '_<_l_e_t_t_e_r_> Go to a previously marked position. + '' Go to the previous position. + ^X^X Same as '. + ESC-m_<_l_e_t_t_e_r_> Clear a mark. + --------------------------------------------------- + A mark is any upper-case or lower-case letter. + Certain marks are predefined: + ^ means beginning of the file + $ means end of the file + --------------------------------------------------------------------------- + + CCHHAANNGGIINNGG FFIILLEESS + + :e [_f_i_l_e] Examine a new file. + ^X^V Same as :e. + :n * Examine the (_N-th) next file from the command line. + :p * Examine the (_N-th) previous file from the command line. + :x * Examine the first (or _N-th) file from the command line. + :d Delete the current file from the command line list. + = ^G :f Print current file name. + --------------------------------------------------------------------------- + + MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS + + -_<_f_l_a_g_> Toggle a command line option [see OPTIONS below]. + --_<_n_a_m_e_> Toggle a command line option, by name. + __<_f_l_a_g_> Display the setting of a command line option. + ___<_n_a_m_e_> Display the setting of an option, by name. + +_c_m_d Execute the less cmd each time a new file is examined. + + !_c_o_m_m_a_n_d Execute the shell command with $SHELL. + #_c_o_m_m_a_n_d Execute the shell command, expanded like a prompt. + |XX_c_o_m_m_a_n_d Pipe file between current pos & mark XX to shell command. + s _f_i_l_e Save input to a file. + v Edit the current file with $VISUAL or $EDITOR. + V Print version number of "less". + --------------------------------------------------------------------------- + + OOPPTTIIOONNSS + + Most options may be changed either on the command line, + or from within less by using the - or -- command. + Options may be given in one of two forms: either a single + character preceded by a -, or a name preceded by --. + + -? ........ --help + Display help (from command line). + -a ........ --search-skip-screen + Search skips current screen. + -A ........ --SEARCH-SKIP-SCREEN + Search starts just after target line. + -b [_N] .... --buffers=[_N] + Number of buffers. + -B ........ --auto-buffers + Don't automatically allocate buffers for pipes. + -c ........ --clear-screen + Repaint by clearing rather than scrolling. + -d ........ --dumb + Dumb terminal. + -D xx_c_o_l_o_r . --color=xx_c_o_l_o_r + Set screen colors. + -e -E .... --quit-at-eof --QUIT-AT-EOF + Quit at end of file. + -f ........ --force + Force open non-regular files. + -F ........ --quit-if-one-screen + Quit if entire file fits on first screen. + -g ........ --hilite-search + Highlight only last match for searches. + -G ........ --HILITE-SEARCH + Don't highlight any matches for searches. + -h [_N] .... --max-back-scroll=[_N] + Backward scroll limit. + -i ........ --ignore-case + Ignore case in searches that do not contain uppercase. + -I ........ --IGNORE-CASE + Ignore case in all searches. + -j [_N] .... --jump-target=[_N] + Screen position of target lines. + -J ........ --status-column + Display a status column at left edge of screen. + -k [_f_i_l_e] . --lesskey-file=[_f_i_l_e] + Use a lesskey file. + -K ........ --quit-on-intr + Exit less in response to ctrl-C. + -L ........ --no-lessopen + Ignore the LESSOPEN environment variable. + -m -M .... --long-prompt --LONG-PROMPT + Set prompt style. + -n ......... --line-numbers + Suppress line numbers in prompts and messages. + -N ......... --LINE-NUMBERS + Display line number at start of each line. + -o [_f_i_l_e] . --log-file=[_f_i_l_e] + Copy to log file (standard input only). + -O [_f_i_l_e] . --LOG-FILE=[_f_i_l_e] + Copy to log file (unconditionally overwrite). + -p [_p_a_t_t_e_r_n] --pattern=[_p_a_t_t_e_r_n] + Start at pattern (from command line). + -P [_p_r_o_m_p_t] --prompt=[_p_r_o_m_p_t] + Define new prompt. + -q -Q .... --quiet --QUIET --silent --SILENT + Quiet the terminal bell. + -r -R .... --raw-control-chars --RAW-CONTROL-CHARS + Output "raw" control characters. + -s ........ --squeeze-blank-lines + Squeeze multiple blank lines. + -S ........ --chop-long-lines + Chop (truncate) long lines rather than wrapping. + -t [_t_a_g] .. --tag=[_t_a_g] + Find a tag. + -T [_t_a_g_s_f_i_l_e] --tag-file=[_t_a_g_s_f_i_l_e] + Use an alternate tags file. + -u -U .... --underline-special --UNDERLINE-SPECIAL + Change handling of backspaces, tabs and carriage returns. + -V ........ --version + Display the version number of "less". + -w ........ --hilite-unread + Highlight first new line after forward-screen. + -W ........ --HILITE-UNREAD + Highlight first new line after any forward movement. + -x [_N[,...]] --tabs=[_N[,...]] + Set tab stops. + -X ........ --no-init + Don't use termcap init/deinit strings. + -y [_N] .... --max-forw-scroll=[_N] + Forward scroll limit. + -z [_N] .... --window=[_N] + Set size of window. + -" [_c[_c]] . --quotes=[_c[_c]] + Set shell quote characters. + -~ ........ --tilde + Don't display tildes after end of file. + -# [_N] .... --shift=[_N] + Set horizontal scroll amount (0 = one half screen width). + --exit-follow-on-close + Exit F command on a pipe when writer closes pipe. + --file-size + Automatically determine the size of the input file. + --follow-name + The F command changes files if the input file is renamed. + --header=[_N[,_M]] + Use N lines and M columns to display file headers. + --incsearch + Search file as each pattern character is typed in. + --intr=_C + Use _C instead of ^X to interrupt a read. + --line-num-width=_N + Set the width of the -N line number field to _N characters. + --modelines=_N + Read _N lines from the input file and look for vim modelines. + --mouse + Enable mouse input. + --no-keypad + Don't send termcap keypad init/deinit strings. + --no-histdups + Remove duplicates from command history. + --no-number-headers + Don't give line numbers to header lines. + --no-search-headers + Don't search in header lines or columns. + --no-vbell + Disable the terminal's visual bell. + --redraw-on-quit + Redraw final screen when quitting. + --rscroll=_C + Set the character used to mark truncated lines. + --save-marks + Retain marks across invocations of less. + --search-options=[EFKNRW-] + Set default options for every search. + --show-preproc-errors + Display a message if preprocessor exits with an error status. + --proc-backspace + Process backspaces for bold/underline. + --SPECIAL-BACKSPACE + Treat backspaces as control characters. + --proc-return + Delete carriage returns before newline. + --SPECIAL-RETURN + Treat carriage returns as control characters. + --proc-tab + Expand tabs to spaces. + --SPECIAL-TAB + Treat tabs as control characters. + --status-col-width=_N + Set the width of the -J status column to _N characters. + --status-line + Highlight or color the entire line containing a mark. + --use-backslash + Subsequent options use backslash as escape char. + --use-color + Enables colored text. + --wheel-lines=_N + Each click of the mouse wheel moves _N lines. + --wordwrap + Wrap lines at spaces. + + + --------------------------------------------------------------------------- + + LLIINNEE EEDDIITTIINNGG + + These keys can be used to edit text being entered + on the "command line" at the bottom of the screen. + + RightArrow ..................... ESC-l ... Move cursor right one character. + LeftArrow ...................... ESC-h ... Move cursor left one character. + ctrl-RightArrow ESC-RightArrow ESC-w ... Move cursor right one word. + ctrl-LeftArrow ESC-LeftArrow ESC-b ... Move cursor left one word. + HOME ........................... ESC-0 ... Move cursor to start of line. + END ............................ ESC-$ ... Move cursor to end of line. + BACKSPACE ................................ Delete char to left of cursor. + DELETE ......................... ESC-x ... Delete char under cursor. + ctrl-BACKSPACE ESC-BACKSPACE ........... Delete word to left of cursor. + ctrl-DELETE .... ESC-DELETE .... ESC-X ... Delete word under cursor. + ctrl-U ......... ESC (MS-DOS only) ....... Delete entire line. + UpArrow ........................ ESC-k ... Retrieve previous command line. + DownArrow ...................... ESC-j ... Retrieve next command line. + TAB ...................................... Complete filename & cycle. + SHIFT-TAB ...................... ESC-TAB Complete filename & reverse cycle. + ctrl-L ................................... Complete filename, list all. diff --git a/wwjcloud/src/app.module.ts b/wwjcloud/src/app.module.ts index 33333bf..1606c18 100644 --- a/wwjcloud/src/app.module.ts +++ b/wwjcloud/src/app.module.ts @@ -32,6 +32,7 @@ import { JobsModule, EventBusModule, NiucloudModule, + SysModule, } from './common'; import { TracingModule, @@ -53,6 +54,16 @@ import { OutboxKafkaForwarderModule } from './core/event/outboxKafkaForwarder.mo // 新增:Site和Pay模块 import { SiteModule } from './common/site/site.module'; import { PayModule } from './common/pay/pay.module'; +// 新增:其他业务模块 +import { WechatModule } from './common/wechat/wechat.module'; +import { WeappModule } from './common/weapp/weapp.module'; +import { AddonModule } from './common/addon/addon.module'; +import { DiyModule } from './common/diy/diy.module'; +import { StatModule } from './common/stat/stat.module'; +import { NoticeModule } from './common/notice/notice.module'; +import { ChannelModule } from './common/channel/channel.module'; +import { HomeModule } from './common/home/home.module'; +import { LoginModule } from './common/login/login.module'; @Module({ imports: [ @@ -103,6 +114,28 @@ import { PayModule } from './common/pay/pay.module'; }), // 认证模块 JwtGlobalModule, + AuthModule, + // 其他业务模块 + SiteModule, + PayModule, + SysModule, + MemberModule, + AdminModule, + RbacModule, + UserModule, + JobsModule, + EventBusModule, + NiucloudModule, + // 新增业务模块 + WechatModule, + WeappModule, + AddonModule, + DiyModule, + StatModule, + NoticeModule, + ChannelModule, + HomeModule, + LoginModule, ], }) export class AppModule {} diff --git a/wwjcloud/src/common/addon/controllers/adminapi/AddonDevelopController.ts b/wwjcloud/src/common/addon/controllers/adminapi/AddonDevelopController.ts index 7f21124..696819c 100644 --- a/wwjcloud/src/common/addon/controllers/adminapi/AddonDevelopController.ts +++ b/wwjcloud/src/common/addon/controllers/adminapi/AddonDevelopController.ts @@ -11,10 +11,12 @@ import { } from '@nestjs/common'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; import { RolesGuard } from '../../../auth/guards/RolesGuard'; +import { Roles } from '../../../auth/decorators/RolesDecorator'; import { AddonDevelopService } from '../../services/admin/AddonDevelopService'; @Controller('adminapi/addon/develop') @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('admin') export class AddonDevelopController { constructor(private readonly addonDevelopService: AddonDevelopService) {} diff --git a/wwjcloud/src/common/addon/controllers/adminapi/AppController.ts b/wwjcloud/src/common/addon/controllers/adminapi/AppController.ts index c41e8ca..bc95d84 100644 --- a/wwjcloud/src/common/addon/controllers/adminapi/AppController.ts +++ b/wwjcloud/src/common/addon/controllers/adminapi/AppController.ts @@ -11,10 +11,12 @@ import { } from '@nestjs/common'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; import { RolesGuard } from '../../../auth/guards/RolesGuard'; +import { Roles } from '../../../auth/decorators/RolesDecorator'; import { AddonAppService } from '../../services/admin/AddonAppService'; @Controller('adminapi/addon/app') @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('admin') export class AppController { constructor(private readonly addonAppService: AddonAppService) {} diff --git a/wwjcloud/src/common/addon/controllers/adminapi/BackupController.ts b/wwjcloud/src/common/addon/controllers/adminapi/BackupController.ts index cd435f0..c5a774e 100644 --- a/wwjcloud/src/common/addon/controllers/adminapi/BackupController.ts +++ b/wwjcloud/src/common/addon/controllers/adminapi/BackupController.ts @@ -10,10 +10,12 @@ import { } from '@nestjs/common'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; import { RolesGuard } from '../../../auth/guards/RolesGuard'; +import { Roles } from '../../../auth/decorators/RolesDecorator'; import { BackupService } from '../../services/admin/BackupService'; @Controller('adminapi/addon/backup') @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('admin') export class BackupController { constructor(private readonly backupService: BackupService) {} diff --git a/wwjcloud/src/common/addon/controllers/adminapi/UpgradeController.ts b/wwjcloud/src/common/addon/controllers/adminapi/UpgradeController.ts index a76aff8..b724eab 100644 --- a/wwjcloud/src/common/addon/controllers/adminapi/UpgradeController.ts +++ b/wwjcloud/src/common/addon/controllers/adminapi/UpgradeController.ts @@ -18,7 +18,14 @@ import { AddonService } from '../../services/admin/AddonService'; export class UpgradeController { constructor(private readonly addonService: AddonService) {} - @Post('upgrade/:addon?') + @Post('upgrade') + async upgradeNoAddon( + @Body() dto: { is_need_backup?: boolean; is_need_cloudbuild?: boolean }, + ) { + return this.addonService.upgrade('', dto); + } + + @Post('upgrade/:addon') async upgrade( @Param('addon') addon: string, @Body() dto: { is_need_backup?: boolean; is_need_cloudbuild?: boolean }, @@ -31,7 +38,12 @@ export class UpgradeController { return this.addonService.executeUpgrade(); } - @Get('upgrade-content/:addon?') + @Get('upgrade-content') + async getUpgradeContentNoAddon() { + return this.addonService.getUpgradeContent(''); + } + + @Get('upgrade-content/:addon') async getUpgradeContent(@Param('addon') addon: string) { return this.addonService.getUpgradeContent(addon); } @@ -41,7 +53,12 @@ export class UpgradeController { return this.addonService.getUpgradeTask(); } - @Get('upgrade-pre-check/:addon?') + @Get('upgrade-pre-check') + async upgradePreCheckNoAddon() { + return this.addonService.upgradePreCheck(''); + } + + @Get('upgrade-pre-check/:addon') async upgradePreCheck(@Param('addon') addon: string) { return this.addonService.upgradePreCheck(addon); } diff --git a/wwjcloud/src/common/admin/controllers/adminapi/AdminController.ts b/wwjcloud/src/common/admin/controllers/adminapi/AdminController.ts index 8db3dd9..e097ef2 100644 --- a/wwjcloud/src/common/admin/controllers/adminapi/AdminController.ts +++ b/wwjcloud/src/common/admin/controllers/adminapi/AdminController.ts @@ -10,6 +10,7 @@ import { UseGuards, UsePipes, ValidationPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, @@ -52,8 +53,11 @@ export class AdminController { @ApiResponse({ status: 200, description: '获取管理员列表成功' }) async getAdminList( @Query() query: QueryAdminDto, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } return await this.adminService.getAdminList(query, site_id); } @@ -63,8 +67,11 @@ export class AdminController { @ApiResponse({ status: 200, description: '获取管理员详情成功' }) async getAdminDetail( @Param('id') id: number, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } return await this.adminService.getAdminDetail(id, site_id); } @@ -75,8 +82,11 @@ export class AdminController { async updateAdmin( @Param('id') id: number, @Body() updateAdminDto: UpdateAdminDto, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } return await this.adminService.updateAdmin(id, updateAdminDto, site_id); } @@ -86,8 +96,11 @@ export class AdminController { @ApiResponse({ status: 200, description: '管理员删除成功' }) async deleteAdmin( @Param('id') id: number, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } await this.adminService.deleteAdmin(id, site_id); return { message: '删除成功' }; } @@ -98,8 +111,11 @@ export class AdminController { @ApiResponse({ status: 200, description: '批量删除成功' }) async batchDeleteAdmins( @Body() data: { uids: number[] }, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } await this.adminService.batchDeleteAdmins(data.uids, site_id); return { message: '批量删除成功' }; } @@ -110,8 +126,11 @@ export class AdminController { @ApiResponse({ status: 200, description: '批量更新状态成功' }) async batchUpdateAdminStatus( @Body() data: BatchUpdateAdminStatusDto, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } await this.adminService.batchUpdateAdminStatus( data.uids, data.status, @@ -126,8 +145,11 @@ export class AdminController { @ApiResponse({ status: 200, description: '批量分配角色成功' }) async batchAssignAdminRoles( @Body() data: BatchAssignRoleDto, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } await this.adminService.batchAssignAdminRoles( data.uids, data.role_ids, @@ -143,8 +165,11 @@ export class AdminController { async resetAdminPassword( @Param('id') id: number, @Body() resetPasswordDto: ResetAdminPasswordDto, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } await this.adminService.resetAdminPassword(id, resetPasswordDto, site_id); return { message: '密码重置成功' }; } @@ -156,8 +181,11 @@ export class AdminController { async updateAdminStatus( @Param('id') id: number, @Body() data: { status: number }, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } await this.adminService.updateAdminStatus(id, data.status, site_id); return { message: '状态更新成功' }; } @@ -169,8 +197,11 @@ export class AdminController { async assignAdminRoles( @Param('id') id: number, @Body() data: { role_ids: string }, - @Query('site_id') site_id: number = 0, + @Query('site_id') site_id: number, ) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } await this.adminService.assignAdminRoles(id, data.role_ids, site_id); return { message: '角色分配成功' }; } @@ -179,7 +210,10 @@ export class AdminController { @Roles('admin') @ApiOperation({ summary: '导出管理员列表' }) @ApiResponse({ status: 200, description: '导出成功' }) - async exportAdmins(@Query('site_id') site_id: number = 0) { + async exportAdmins(@Query('site_id') site_id: number) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } return await this.adminService.exportAdmins(site_id); } @@ -187,7 +221,10 @@ export class AdminController { @Roles('admin') @ApiOperation({ summary: '获取管理员统计信息' }) @ApiResponse({ status: 200, description: '获取统计信息成功' }) - async getAdminStats(@Query('site_id') site_id: number = 0) { + async getAdminStats(@Query('site_id') site_id: number) { + if (!site_id) { + throw new UnauthorizedException('site_id is required'); + } return await this.adminService.getAdminStats(site_id); } } diff --git a/wwjcloud/src/common/admin/entities/SysUser.ts b/wwjcloud/src/common/admin/entities/SysUser.ts index 878a2d0..204dbc5 100644 --- a/wwjcloud/src/common/admin/entities/SysUser.ts +++ b/wwjcloud/src/common/admin/entities/SysUser.ts @@ -1,10 +1,9 @@ -import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; +import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm'; import { SysUserRole } from './SysUserRole'; import { SysUserLog } from './SysUserLog'; @Entity('sys_user') -export class SysUser extends BaseEntity { +export class SysUser { @PrimaryGeneratedColumn({ name: 'uid' }) uid: number; @@ -32,6 +31,18 @@ export class SysUser extends BaseEntity { @Column({ name: 'status', type: 'tinyint', default: 1 }) status: number; + @Column({ name: 'is_del', type: 'tinyint', default: 0 }) + is_del: number; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0 }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0 }) + update_time: number; + + @DeleteDateColumn({ name: 'delete_time', type: 'int', default: 0 }) + delete_time: number; + // 关联关系 @OneToMany(() => SysUserRole, (userRole) => userRole.user) user_role: SysUserRole[]; diff --git a/wwjcloud/src/common/admin/entities/SysUserRole.ts b/wwjcloud/src/common/admin/entities/SysUserRole.ts index 145f96e..7f12d06 100644 --- a/wwjcloud/src/common/admin/entities/SysUserRole.ts +++ b/wwjcloud/src/common/admin/entities/SysUserRole.ts @@ -23,19 +23,16 @@ export class SysUserRole { @Column({ name: 'role_ids', type: 'varchar', length: 255, default: '' }) role_ids: string; - @CreateDateColumn({ name: 'create_time', type: 'int' }) + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '添加时间' }) create_time: number; - @UpdateDateColumn({ name: 'update_time', type: 'int' }) - update_time: number; - - @Column({ name: 'is_admin', type: 'int', default: 0 }) + @Column({ name: 'is_admin', type: 'int', default: 0, comment: '是否是超级管理员' }) is_admin: number; - @Column({ name: 'status', type: 'int', default: 1 }) + @Column({ name: 'status', type: 'int', default: 1, comment: '状态' }) status: number; - @Column({ name: 'delete_time', type: 'int', default: 0 }) + @Column({ name: 'delete_time', type: 'int', default: 0, comment: '删除时间' }) delete_time: number; // 关联关系 diff --git a/wwjcloud/src/common/auth/auth.module.ts b/wwjcloud/src/common/auth/auth.module.ts index 8ddf693..409e27c 100644 --- a/wwjcloud/src/common/auth/auth.module.ts +++ b/wwjcloud/src/common/auth/auth.module.ts @@ -1,8 +1,9 @@ import { Module, forwardRef, Global } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { ConfigModule } from '@nestjs/config'; import { AuthToken } from './entities/AuthToken'; +import { SysConfig } from '../settings/entities/sys-config.entity'; +import { SysUser } from '../admin/entities/SysUser'; import { AuthService } from './services/AuthService'; import { AuthController } from './controllers/AuthController'; import { LoginApiController } from './controllers/api/LoginApiController'; @@ -21,6 +22,7 @@ import { CoreLoginConfigService } from './services/core/CoreLoginConfigService'; import { JwtAuthGuard } from './guards/JwtAuthGuard'; import { RolesGuard } from './guards/RolesGuard'; import { JwtGlobalModule } from './jwt.module'; +import { RedisProvider } from '../../vendor/redis/redis.provider'; // 导入Admin和Member模块 import { AdminModule } from '../admin/admin.module'; @@ -30,45 +32,46 @@ import { MemberModule } from '../member/member.module'; @Module({ imports: [ PassportModule, - TypeOrmModule.forFeature([AuthToken]), + TypeOrmModule.forFeature([AuthToken, SysConfig, SysUser]), JwtGlobalModule, // 导入Admin和Member模块以使用其服务 forwardRef(() => AdminModule), forwardRef(() => MemberModule), ], providers: [ - AuthService, - LoginApiService, + AuthService, + LoginApiService, LoginConfigApiService, RegisterApiService, - CaptchaService, + CaptchaService, LoginConfigService, - CoreAuthService, - CoreCaptchaService, + CoreAuthService, + CoreCaptchaService, CoreLoginConfigService, - JwtAuthGuard, - RolesGuard + RedisProvider, + JwtAuthGuard, + RolesGuard, ], controllers: [ - AuthController, - LoginApiController, + AuthController, + LoginApiController, LoginConfigApiController, RegisterApiController, - CaptchaController, - LoginConfigController + CaptchaController, + LoginConfigController, ], exports: [ - AuthService, - LoginApiService, + AuthService, + LoginApiService, LoginConfigApiService, RegisterApiService, - CaptchaService, + CaptchaService, LoginConfigService, - CoreAuthService, - CoreCaptchaService, + CoreAuthService, + CoreCaptchaService, CoreLoginConfigService, - JwtAuthGuard, - RolesGuard + JwtAuthGuard, + RolesGuard, ], }) export class AuthModule {} diff --git a/wwjcloud/src/common/auth/controllers/adminapi/CaptchaController.ts b/wwjcloud/src/common/auth/controllers/adminapi/CaptchaController.ts index 6f80738..fd4fc33 100644 --- a/wwjcloud/src/common/auth/controllers/adminapi/CaptchaController.ts +++ b/wwjcloud/src/common/auth/controllers/adminapi/CaptchaController.ts @@ -15,23 +15,20 @@ export class CaptchaController { @ApiOperation({ summary: '创建验证码' }) @ApiResponse({ status: 200, description: '创建成功' }) async create(@Query() query: CaptchaCreateDto) { - const data = await this.captchaService.create(query); - return { code: 200, message: '创建成功', data }; + return await this.captchaService.create(query); } @Post('check') @ApiOperation({ summary: '一次校验验证码' }) @ApiResponse({ status: 200, description: '校验成功' }) async check(@Body() body: CaptchaCheckDto) { - const data = await this.captchaService.check(body); - return { code: 200, message: '校验成功', data }; + return await this.captchaService.check(body); } @Post('verification') @ApiOperation({ summary: '二次校验验证码' }) @ApiResponse({ status: 200, description: '校验成功' }) async verification(@Body() body: CaptchaVerificationDto) { - const data = await this.captchaService.verification(body); - return { code: 200, message: '校验成功', data }; + return await this.captchaService.verification(body); } } diff --git a/wwjcloud/src/common/auth/controllers/adminapi/LoginConfigController.ts b/wwjcloud/src/common/auth/controllers/adminapi/LoginConfigController.ts index 2ee169f..161d5b1 100644 --- a/wwjcloud/src/common/auth/controllers/adminapi/LoginConfigController.ts +++ b/wwjcloud/src/common/auth/controllers/adminapi/LoginConfigController.ts @@ -1,10 +1,11 @@ -import { Controller, Get, Post, Body, UseGuards } from '@nestjs/common'; +import { Controller, Get, Post, Body, UseGuards, Request, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { JwtAuthGuard } from '../../guards/JwtAuthGuard'; import { RolesGuard } from '../../guards/RolesGuard'; import { Roles } from '../../decorators/RolesDecorator'; import { LoginConfigService } from '../../services/admin/LoginConfigService'; import { LoginConfigDto } from '../../dto/admin/LoginConfigDto'; +import { LoginConfig } from '../../services/core/CoreLoginConfigService'; @ApiTags('登录配置管理') @Controller('adminapi/auth/login-config') @@ -16,16 +17,22 @@ export class LoginConfigController { @Get('config') @ApiOperation({ summary: '获取登录设置' }) @ApiResponse({ status: 200, description: '获取成功' }) - async getConfig() { - const data = await this.loginConfigService.getConfig(); - return { code: 200, message: '获取成功', data }; + async getConfig(@Request() req: any): Promise { + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.loginConfigService.getConfig(siteId); } @Post('config') @ApiOperation({ summary: '设置登录配置' }) @ApiResponse({ status: 200, description: '设置成功' }) - async setConfig(@Body() body: LoginConfigDto) { - const data = await this.loginConfigService.setConfig(body); - return { code: 200, message: '设置成功', data }; + async setConfig(@Request() req: any, @Body() body: LoginConfigDto) { + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.loginConfigService.setConfig(body, siteId); } } diff --git a/wwjcloud/src/common/auth/controllers/api/LoginConfigApiController.ts b/wwjcloud/src/common/auth/controllers/api/LoginConfigApiController.ts index 96d6671..5fbc282 100644 --- a/wwjcloud/src/common/auth/controllers/api/LoginConfigApiController.ts +++ b/wwjcloud/src/common/auth/controllers/api/LoginConfigApiController.ts @@ -8,6 +8,7 @@ import { } from '@nestjs/common'; import { Public } from '../../../auth/decorators/public.decorator'; import { LoginConfigApiService } from '../../services/api/LoginConfigApiService'; +import { LoginConfig } from '../../services/core/CoreLoginConfigService'; @Controller('api/login/config') export class LoginConfigApiController { @@ -18,7 +19,7 @@ export class LoginConfigApiController { */ @Get('info') @Public() - async getInfo(@Query() query: any) { + async getInfo(@Query() query: any): Promise { return this.loginConfigApiService.getInfo(query); } diff --git a/wwjcloud/src/common/auth/dto/admin/LoginConfigDto.ts b/wwjcloud/src/common/auth/dto/admin/LoginConfigDto.ts index 281e65f..e5d7dc0 100644 --- a/wwjcloud/src/common/auth/dto/admin/LoginConfigDto.ts +++ b/wwjcloud/src/common/auth/dto/admin/LoginConfigDto.ts @@ -48,4 +48,26 @@ export class LoginConfigDto { lockoutDuration?: number; lockoutType?: string; }; + + // PHP 特有字段 + @ApiProperty({ description: '是否启用授权注册', required: false }) + @IsOptional() + isAuthRegister?: boolean; + + @ApiProperty({ description: '是否强制获取用户信息', required: false }) + @IsOptional() + isForceAccessUserInfo?: boolean; + + @ApiProperty({ description: '是否绑定手机号', required: false }) + @IsOptional() + isBindMobile?: boolean; + + @ApiProperty({ description: '是否显示协议', required: false }) + @IsOptional() + agreementShow?: boolean; + + @ApiProperty({ description: '描述信息', required: false }) + @IsOptional() + @IsString() + desc?: string; } diff --git a/wwjcloud/src/common/auth/services/admin/LoginConfigService.ts b/wwjcloud/src/common/auth/services/admin/LoginConfigService.ts index 8e0a56d..4d61012 100644 --- a/wwjcloud/src/common/auth/services/admin/LoginConfigService.ts +++ b/wwjcloud/src/common/auth/services/admin/LoginConfigService.ts @@ -1,16 +1,16 @@ import { Injectable } from '@nestjs/common'; -import { CoreLoginConfigService } from '../core/CoreLoginConfigService'; +import { CoreLoginConfigService, LoginConfig } from '../core/CoreLoginConfigService'; import { LoginConfigDto } from '../../dto/admin/LoginConfigDto'; @Injectable() export class LoginConfigService { constructor(private readonly coreLoginConfig: CoreLoginConfigService) {} - async getConfig() { - return await this.coreLoginConfig.getConfig(); + async getConfig(siteId: number): Promise { + return await this.coreLoginConfig.getConfig(siteId); } - async setConfig(dto: LoginConfigDto) { - return await this.coreLoginConfig.setConfig(dto); + async setConfig(dto: LoginConfigDto, siteId: number) { + return await this.coreLoginConfig.setConfig(dto, siteId); } } diff --git a/wwjcloud/src/common/auth/services/api/LoginConfigApiService.ts b/wwjcloud/src/common/auth/services/api/LoginConfigApiService.ts index a93c89c..5c55b92 100644 --- a/wwjcloud/src/common/auth/services/api/LoginConfigApiService.ts +++ b/wwjcloud/src/common/auth/services/api/LoginConfigApiService.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, UnauthorizedException } from '@nestjs/common'; import { CoreLoginConfigService } from '../core/CoreLoginConfigService'; @Injectable() @@ -9,35 +9,55 @@ export class LoginConfigApiService { * 获取登录配置 */ async getInfo(query: any) { - return this.coreLoginConfigService.getInfo(query); + const siteId = query.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } + return this.coreLoginConfigService.getInfo(siteId, query); } /** * 获取登录方式 */ async getMethods(query: any) { - return this.coreLoginConfigService.getMethods(query); + const siteId = query.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } + return this.coreLoginConfigService.getMethods(siteId, query); } /** * 获取验证码配置 */ async getCaptchaConfig(query: any) { - return this.coreLoginConfigService.getCaptchaConfig(query); + const siteId = query.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } + return this.coreLoginConfigService.getCaptchaConfig(siteId, query); } /** * 获取第三方登录配置 */ async getThirdPartyConfig(query: any) { - return this.coreLoginConfigService.getThirdPartyConfig(query); + const siteId = query.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } + return this.coreLoginConfigService.getThirdPartyConfig(siteId, query); } /** * 获取注册配置 */ async getRegisterConfig(query: any) { - return this.coreLoginConfigService.getRegisterConfig(query); + const siteId = query.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } + return this.coreLoginConfigService.getRegisterConfig(siteId, query); } /** diff --git a/wwjcloud/src/common/auth/services/core/CoreAuthService.ts b/wwjcloud/src/common/auth/services/core/CoreAuthService.ts index af97729..da09744 100644 --- a/wwjcloud/src/common/auth/services/core/CoreAuthService.ts +++ b/wwjcloud/src/common/auth/services/core/CoreAuthService.ts @@ -1,26 +1,23 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { BaseService } from '@wwjCore/base/BaseService'; import { SysUser } from '../../../admin/entities/SysUser'; import * as bcrypt from 'bcrypt'; import * as crypto from 'crypto'; @Injectable() -export class CoreAuthService extends BaseService { +export class CoreAuthService { constructor( @InjectRepository(SysUser) - private userRepository: Repository, - ) { - super(userRepository); - } + private readonly userRepository: Repository, + ) {} /** * 验证用户凭据 */ async validateUser(username: string, password: string, site_id: number) { const user = await this.userRepository.findOne({ - where: { username, site_id, status: 1 }, + where: { username, status: 1 }, }); if (!user) { @@ -49,7 +46,7 @@ export class CoreAuthService extends BaseService { */ async checkUserExists(username: string, site_id: number) { const user = await this.userRepository.findOne({ - where: { username, site_id }, + where: { username }, }); return !!user; } @@ -60,15 +57,20 @@ export class CoreAuthService extends BaseService { async createUser(userData: any) { const hashedPassword = await bcrypt.hash(userData.password, 10); - const user = this.userRepository.create({ + const userDataWithHash = { ...userData, password: hashedPassword, status: 1, - create_time: Math.floor(Date.now() / 1000), - }); + }; - const saved = await this.userRepository.save(user); - return Array.isArray(saved) ? saved[0] : saved; + const user = this.userRepository.create({ + ...userDataWithHash, + create_time: Math.floor(Date.now() / 1000), + update_time: Math.floor(Date.now() / 1000), + is_del: 0, + delete_time: 0, + } as any); + return await this.userRepository.save(user as any); } /** diff --git a/wwjcloud/src/common/auth/services/core/CoreCaptchaService.ts b/wwjcloud/src/common/auth/services/core/CoreCaptchaService.ts index d006fb6..3b33e1e 100644 --- a/wwjcloud/src/common/auth/services/core/CoreCaptchaService.ts +++ b/wwjcloud/src/common/auth/services/core/CoreCaptchaService.ts @@ -1,17 +1,26 @@ import { Injectable } from '@nestjs/common'; +import { RedisProvider } from '../../../../vendor/redis/redis.provider'; import { CaptchaCreateDto, CaptchaCheckDto, CaptchaVerificationDto } from '../../dto/admin/CaptchaDto'; @Injectable() export class CoreCaptchaService { - constructor() {} + private readonly CAPTCHA_PREFIX = 'captcha:'; + private readonly CAPTCHA_TTL_SECONDS = 300; // 5 min + + constructor(private readonly redisProvider: RedisProvider) {} async create(dto: CaptchaCreateDto) { // 对齐 PHP: CaptchaService->create() const captchaId = this.generateCaptchaId(); const captchaValue = this.generateCaptchaValue(dto.length || 4); - // TODO: 生成验证码图片并存储 - // const captchaImage = await this.generateCaptchaImage(captchaValue, dto); + // 持久化到 Redis + const client = this.redisProvider.getClient(); + await client.setex( + `${this.CAPTCHA_PREFIX}${captchaId}`, + this.CAPTCHA_TTL_SECONDS, + captchaValue, + ); return { captchaId, @@ -23,7 +32,6 @@ export class CoreCaptchaService { async check(dto: CaptchaCheckDto) { // 对齐 PHP: CaptchaService->check() - // TODO: 从缓存或数据库验证验证码 const isValid = await this.validateCaptcha(dto.captchaId, dto.captchaValue); if (!isValid) { @@ -35,7 +43,6 @@ export class CoreCaptchaService { async verification(dto: CaptchaVerificationDto) { // 对齐 PHP: CaptchaService->verification() - // TODO: 二次验证逻辑,可能包括短信验证、邮箱验证等 const isValid = await this.validateCaptcha(dto.captchaId, dto.captchaValue); if (!isValid) { @@ -71,14 +78,20 @@ export class CoreCaptchaService { } private async validateCaptcha(captchaId: string, captchaValue: string): Promise { - // TODO: 从Redis或数据库验证验证码 - // 临时实现 - return captchaValue.length >= 4; + const client = this.redisProvider.getClient(); + const key = `${this.CAPTCHA_PREFIX}${captchaId}`; + const stored = await client.get(key); + if (!stored) return false; + const ok = stored.toLowerCase() === (captchaValue || '').toLowerCase(); + if (ok) { + // 一次性验证码:校验成功后删除 + await client.del(key); + } + return ok; } private async performSecondVerification(params?: Record): Promise { - // TODO: 实现二次验证逻辑 - // 可能包括短信验证、邮箱验证、人脸识别等 + // 可以在此扩展短信/邮箱等二次校验 return true; } } diff --git a/wwjcloud/src/common/auth/services/core/CoreLoginConfigService.ts b/wwjcloud/src/common/auth/services/core/CoreLoginConfigService.ts index 8ddd1f2..a2cfbd4 100644 --- a/wwjcloud/src/common/auth/services/core/CoreLoginConfigService.ts +++ b/wwjcloud/src/common/auth/services/core/CoreLoginConfigService.ts @@ -1,12 +1,99 @@ import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { SysConfig } from '../../../settings/entities/sys-config.entity'; +import { BaseService } from '../../../../core/base/BaseService'; import { LoginConfigDto } from '../../dto/admin/LoginConfigDto'; -@Injectable() -export class CoreLoginConfigService { - constructor() {} +export interface LoginConfig { + isCaptcha: number; + isSiteCaptcha: number; + bg: string; + siteBg: string; + loginMethods: { + username: boolean; + email: boolean; + mobile: boolean; + wechat: boolean; + qq: boolean; + }; + passwordPolicy: { + minLength: number; + requireSpecialChar: boolean; + requireNumber: boolean; + requireUppercase: boolean; + }; + loginLimit: { + maxAttempts: number; + lockoutDuration: number; + lockoutType: string; + }; + // PHP 特有字段 + isAuthRegister: boolean; + isForceAccessUserInfo: boolean; + isBindMobile: boolean; + agreementShow: boolean; + desc: string; +} + +@Injectable() +export class CoreLoginConfigService extends BaseService { + constructor( + @InjectRepository(SysConfig) + configRepository: Repository, + ) { + super(configRepository); + } + + async getConfig(siteId: number): Promise { + // 对齐 PHP: CoreMemberConfigService->getLoginConfig() + const config = await this.repository.findOne({ + where: { + config_key: 'LOGIN', + site_id: siteId + }, + }); + + if (config?.value) { + let configData: any; + try { + configData = JSON.parse(config.value); + } catch { + configData = {}; + } + + return { + isCaptcha: 1, // 默认启用验证码 + isSiteCaptcha: 1, // 默认启用站点验证码 + bg: configData.bg_url || '', // 登录背景图 + siteBg: configData.bg_url || '', // 站点登录背景图 + loginMethods: { + username: configData.is_username === 1, + email: false, // PHP 中没有邮箱登录 + mobile: configData.is_mobile === 1, + wechat: false, // 微信登录通过其他方式处理 + qq: false, + }, + passwordPolicy: { + minLength: 6, + requireSpecialChar: false, + requireNumber: false, + requireUppercase: false, + }, + loginLimit: { + maxAttempts: 5, + lockoutDuration: 30, // 分钟 + lockoutType: 'ip', // ip 或 username + }, + // PHP 特有字段 + isAuthRegister: configData.is_auth_register === 1, + isForceAccessUserInfo: configData.is_force_access_user_info === 1, + isBindMobile: configData.is_bind_mobile === 1, + agreementShow: configData.agreement_show === 1, + desc: configData.desc || '精选好物,购物优惠的省钱平台', + }; + } - async getConfig() { - // 对齐 PHP: ConfigService->getConfig() return { isCaptcha: 1, // 默认启用验证码 isSiteCaptcha: 1, // 默认启用站点验证码 @@ -14,8 +101,8 @@ export class CoreLoginConfigService { siteBg: '', // 站点登录背景图 loginMethods: { username: true, - email: true, - mobile: true, + email: false, + mobile: false, wechat: false, qq: false, }, @@ -30,68 +117,81 @@ export class CoreLoginConfigService { lockoutDuration: 30, // 分钟 lockoutType: 'ip', // ip 或 username }, + // PHP 特有字段 + isAuthRegister: true, + isForceAccessUserInfo: false, + isBindMobile: false, + agreementShow: false, + desc: '精选好物,购物优惠的省钱平台', }; } - async setConfig(dto: LoginConfigDto) { - // 对齐 PHP: ConfigService->setConfig() + async setConfig(dto: LoginConfigDto, siteId: number) { + // 对齐 PHP: CoreMemberConfigService->setLoginConfig() const config = { - isCaptcha: dto.isCaptcha ?? 1, - isSiteCaptcha: dto.isSiteCaptcha ?? 1, - bg: dto.bg ?? '', - siteBg: dto.siteBg ?? '', - loginMethods: dto.loginMethods ?? { - username: true, - email: true, - mobile: true, - wechat: false, - qq: false, - }, - passwordPolicy: dto.passwordPolicy ?? { - minLength: 6, - requireSpecialChar: false, - requireNumber: false, - requireUppercase: false, - }, - loginLimit: dto.loginLimit ?? { - maxAttempts: 5, - lockoutDuration: 30, - lockoutType: 'ip', - }, + is_username: dto.loginMethods?.username ? 1 : 0, + is_mobile: dto.loginMethods?.mobile ? 1 : 0, + is_auth_register: dto.isAuthRegister ? 1 : 0, + is_force_access_user_info: dto.isForceAccessUserInfo ? 1 : 0, + is_bind_mobile: dto.isBindMobile ? 1 : 0, + agreement_show: dto.agreementShow ? 1 : 0, + bg_url: dto.bg || '', + desc: dto.desc || '精选好物,购物优惠的省钱平台', }; - // TODO: 保存配置到数据库或配置文件 - // await this.saveConfig(config); + const existed = await this.repository.findOne({ + where: { + config_key: 'LOGIN', + site_id: siteId + }, + }); + + if (existed) { + await this.update(existed.id, { + value: JSON.stringify(config), + }); + } else { + await this.create({ + site_id: siteId, + config_key: 'LOGIN', + value: JSON.stringify(config), + }); + } return { success: true, message: '配置保存成功' }; } // 兼容 API 层调用的方法(按 PHP 语义拆分) - async getInfo(query?: any) { - return this.getConfig(); + async getInfo(siteId: number, _query?: any): Promise { + return this.getConfig(siteId); } - async getMethods(query?: any) { - const config = await this.getConfig(); + async getMethods(siteId: number, _query?: any) { + const config = await this.getConfig(siteId); return config.loginMethods; } - async getCaptchaConfig(query?: any) { - const config = await this.getConfig(); + async getCaptchaConfig(siteId: number, _query?: any) { + const config = await this.getConfig(siteId); return { isCaptcha: config.isCaptcha, isSiteCaptcha: config.isSiteCaptcha }; } - async getThirdPartyConfig(query?: any) { - const config = await this.getConfig(); + async getThirdPartyConfig(siteId: number, _query?: any) { + const config = await this.getConfig(siteId); return { wechat: config.loginMethods.wechat, qq: config.loginMethods.qq }; } - async getRegisterConfig(query?: any) { - const config = await this.getConfig(); + async getRegisterConfig(siteId: number, _query?: any) { + const config = await this.getConfig(siteId); return { passwordPolicy: config.passwordPolicy }; } - async getForgotPasswordConfig(query?: any) { + getForgotPasswordConfig(_query?: any) { return { ways: ['email', 'mobile'] }; } + + private buildConfigKey(siteId: number): string { + // 兼容无 site_id 字段的实体定义,使用 key 后缀区分站点 + return `login_config:site:${siteId || 0}`; + } } diff --git a/wwjcloud/src/common/diy/entities/DiyForm.ts b/wwjcloud/src/common/diy/entities/DiyForm.ts index c7e21a6..e480207 100644 --- a/wwjcloud/src/common/diy/entities/DiyForm.ts +++ b/wwjcloud/src/common/diy/entities/DiyForm.ts @@ -1,36 +1,50 @@ -import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; +import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn, UpdateDateColumn } from 'typeorm'; import { DiyFormFields } from './DiyFormFields'; import { DiyFormRecords } from './DiyFormRecords'; @Entity('diy_form') -export class DiyForm extends BaseEntity { +export class DiyForm { @PrimaryGeneratedColumn({ name: 'form_id' }) form_id: number; - @Column({ name: 'title', type: 'varchar', length: 255, comment: '表单标题' }) + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; + + @Column({ name: 'page_title', type: 'varchar', length: 255, default: '', comment: '表单名称(用于后台展示)' }) + page_title: string; + + @Column({ name: 'title', type: 'varchar', length: 255, default: '', comment: '表单名称(用于前台展示)' }) title: string; - @Column({ name: 'type', type: 'varchar', length: 50, comment: '表单类型' }) + @Column({ name: 'type', type: 'varchar', length: 255, default: '', comment: '表单类型' }) type: string; - @Column({ name: 'value', type: 'text', nullable: true, comment: '表单配置JSON' }) - value: string; - - @Column({ name: 'share', type: 'text', nullable: true, comment: '分享配置JSON' }) - share: string; - - @Column({ name: 'status', type: 'tinyint', default: 1, comment: '状态:0=禁用,1=启用' }) + @Column({ name: 'status', type: 'tinyint', default: 0, comment: '状态(0,关闭,1:开启)' }) status: number; - @Column({ name: 'is_default', type: 'tinyint', default: 0, comment: '是否默认:0=否,1=是' }) - is_default: number; + @Column({ name: 'template', type: 'varchar', length: 255, default: '', comment: '模板名称' }) + template: string; - @Column({ name: 'addon', type: 'varchar', length: 100, default: '', comment: '插件标识' }) + @Column({ name: 'value', type: 'longtext', nullable: true, comment: '表单数据,json格式,包含展示组件' }) + value: string; + + @Column({ name: 'addon', type: 'varchar', length: 255, default: '', comment: '所属插件标识' }) addon: string; - @Column({ name: 'sort', type: 'int', default: 0, comment: '排序' }) - sort: number; + @Column({ name: 'share', type: 'varchar', length: 1000, default: '', comment: '分享内容' }) + share: string; + + @Column({ name: 'write_num', type: 'int', default: 0, comment: '表单填写总数量' }) + write_num: number; + + @Column({ name: 'remark', type: 'varchar', length: 255, default: '', comment: '备注说明' }) + remark: string; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '创建时间' }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '更新时间' }) + update_time: number; // 关联字段 @OneToMany(() => DiyFormFields, fields => fields.form) diff --git a/wwjcloud/src/common/diy/entities/DiyPage.ts b/wwjcloud/src/common/diy/entities/DiyPage.ts index c5fe8ce..d8efd2d 100644 --- a/wwjcloud/src/common/diy/entities/DiyPage.ts +++ b/wwjcloud/src/common/diy/entities/DiyPage.ts @@ -1,12 +1,11 @@ -import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm'; /** * 自定义页面实体 * 对应数据库表: diy_page */ @Entity('diy_page') -export class DiyPage extends BaseEntity { +export class DiyPage { @PrimaryGeneratedColumn({ name: 'id' }) id: number; @@ -43,5 +42,12 @@ export class DiyPage extends BaseEntity { @Column({ name: 'visit_count', type: 'int', default: 0, comment: '访问量' }) visit_count: number; - // create_time 和 update_time 由 BaseEntity 提供 + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '创建时间' }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '更新时间' }) + update_time: number; } diff --git a/wwjcloud/src/common/diy/services/admin/DiyService.ts b/wwjcloud/src/common/diy/services/admin/DiyService.ts index 427e4ed..5a92e80 100644 --- a/wwjcloud/src/common/diy/services/admin/DiyService.ts +++ b/wwjcloud/src/common/diy/services/admin/DiyService.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, UnauthorizedException } from '@nestjs/common'; import { CoreDiyService } from '../core/CoreDiyService'; import { DiyPage } from '../../entities/DiyPage'; @@ -74,7 +74,10 @@ export class DiyService { * 控制器所需:分页 */ async getPage(query: any) { - const { site_id = 0, key } = query || {}; + const { site_id, key } = query || {}; + if (!site_id) { + throw new Error('缺少 site_id 参数'); + } const list = await this.coreDiyService.getPageListByType(Number(site_id), key); const page = Number(query?.page || 1); const limit = Number(query?.limit || list.length || 20); @@ -88,9 +91,12 @@ export class DiyService { } async add(data: any) { + if (!data.site_id) { + throw new UnauthorizedException('Missing site_id'); + } // 对齐 PHP 字段映射 const payload = { - site_id: data.site_id || 0, + site_id: data.site_id, name: data.page_name, type: data.page_type || data.key || 'custom', value: JSON.stringify(data.page_data || {}), @@ -118,7 +124,7 @@ export class DiyService { const info = await this.coreDiyService.getPageInfo(pageId); if (!info) return null; return this.coreDiyService.addPage({ - site_id: (info as any).site_id || 0, + site_id: (info as any).site_id, name: newName, type: (info as any).type, value: (info as any).value, @@ -136,7 +142,7 @@ export class DiyService { const info = await this.coreDiyService.getPageInfo(pageId); if (!info) return false; // 对齐 PHP:设置为默认 - await this.coreDiyService.setDefaultPage((info as any).site_id || 0, (info as any).name, (info as any).id); + await this.coreDiyService.setDefaultPage((info as any).site_id, (info as any).name, (info as any).id); return true; } diff --git a/wwjcloud/src/common/diy/services/core/CoreDiyFormService.ts b/wwjcloud/src/common/diy/services/core/CoreDiyFormService.ts index 5ce3e26..4e758cb 100644 --- a/wwjcloud/src/common/diy/services/core/CoreDiyFormService.ts +++ b/wwjcloud/src/common/diy/services/core/CoreDiyFormService.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, In } from 'typeorm'; -import { BaseService } from '../../../../core/base/BaseService'; import { DiyForm } from '../../entities/DiyForm'; import { DiyFormFields } from '../../entities/DiyFormFields'; import { DiyFormRecords } from '../../entities/DiyFormRecords'; @@ -14,7 +13,7 @@ import { DiyFormWriteConfig } from '../../entities/DiyFormWriteConfig'; * 对应PHP: CoreDiyFormService */ @Injectable() -export class CoreDiyFormService extends BaseService { +export class CoreDiyFormService { constructor( @InjectRepository(DiyForm) private readonly diyFormRepository: Repository, @@ -28,9 +27,7 @@ export class CoreDiyFormService extends BaseService { private readonly diyFormSubmitConfigRepository: Repository, @InjectRepository(DiyFormWriteConfig) private readonly diyFormWriteConfigRepository: Repository, - ) { - super(diyFormRepository); - } + ) {} /** * 分页查询表单列表 @@ -160,9 +157,7 @@ export class CoreDiyFormService extends BaseService { 'value', 'share', 'status', - 'is_default', 'addon', - 'sort', 'create_time', 'update_time', ], @@ -297,13 +292,13 @@ export class CoreDiyFormService extends BaseService { // 先取消所有默认 await this.diyFormRepository.update( { site_id: siteId }, - { is_default: 0, update_time: Math.floor(Date.now() / 1000) }, + { status: 0, update_time: Math.floor(Date.now() / 1000) }, ); // 设置当前为默认 const result = await this.diyFormRepository.update( { form_id: formId, site_id: siteId }, - { is_default: 1, update_time: Math.floor(Date.now() / 1000) }, + { status: 1, update_time: Math.floor(Date.now() / 1000) }, ); return (result.affected || 0) > 0; diff --git a/wwjcloud/src/common/diy/services/core/CoreDiyService.ts b/wwjcloud/src/common/diy/services/core/CoreDiyService.ts index 063e6f1..afd73f3 100644 --- a/wwjcloud/src/common/diy/services/core/CoreDiyService.ts +++ b/wwjcloud/src/common/diy/services/core/CoreDiyService.ts @@ -1,13 +1,12 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { BaseService } from '@wwjCore/base/BaseService'; import { DiyPage } from '../../entities/DiyPage'; import { DiyRoute } from '../../entities/DiyRoute'; import { DiyTheme } from '../../entities/DiyTheme'; @Injectable() -export class CoreDiyService extends BaseService { +export class CoreDiyService { constructor( @InjectRepository(DiyPage) private diyPageRepository: Repository, @@ -15,9 +14,7 @@ export class CoreDiyService extends BaseService { private diyRouteRepository: Repository, @InjectRepository(DiyTheme) private diyThemeRepository: Repository, - ) { - super(diyPageRepository); - } + ) {} /** * 获取DIY页面列表 @@ -140,6 +137,33 @@ export class CoreDiyService extends BaseService { /** * 设置默认页面 */ + /** + * 删除页面 + */ + async delete(pageId: number) { + const result = await this.diyPageRepository.delete({ id: pageId }); + return (result.affected || 0) > 0; + } + + /** + * 创建页面 + */ + async create(data: any) { + const page = this.diyPageRepository.create(data); + return await this.diyPageRepository.save(page); + } + + /** + * 更新页面 + */ + async update(pageId: number, data: any) { + const result = await this.diyPageRepository.update( + { id: pageId }, + { ...data, update_time: Math.floor(Date.now() / 1000) } + ); + return (result.affected || 0) > 0; + } + async setDefaultPage(site_id: number, name: string, page_id: number) { // 先取消其他页面的默认状态 await this.diyPageRepository.update( diff --git a/wwjcloud/src/common/home/home.module.ts b/wwjcloud/src/common/home/home.module.ts new file mode 100644 index 0000000..5e79867 --- /dev/null +++ b/wwjcloud/src/common/home/home.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { HomeSiteService } from './services/admin/HomeSiteService'; +import { SiteController } from './controllers/adminapi/SiteController'; + +@Module({ + controllers: [SiteController], + providers: [HomeSiteService], + exports: [HomeSiteService], +}) +export class HomeModule {} diff --git a/wwjcloud/src/common/jobs/jobs.module.ts b/wwjcloud/src/common/jobs/jobs.module.ts index 38cc4fb..d54b44e 100644 --- a/wwjcloud/src/common/jobs/jobs.module.ts +++ b/wwjcloud/src/common/jobs/jobs.module.ts @@ -1,5 +1,10 @@ -import { Module } from '@nestjs/common'; +import { Module, forwardRef } from '@nestjs/common'; import { VendorModule } from '../../vendor'; +import { PayModule } from '../pay/pay.module'; +import { SiteModule } from '../site/site.module'; +import { SysModule } from '../sys/sys.module'; +import { ScheduleModule } from '../schedule/schedule.module'; +import { MemberModule } from '../member/member.module'; import { JobsService } from './jobs.service'; import { OnModuleInit } from '@nestjs/common'; import { PaymentProcessors } from './processors/payment'; @@ -12,7 +17,7 @@ import { UpgradeProcessors } from './processors/upgrade'; import { WxoplatformProcessors } from './processors/wxoplatform'; @Module({ - imports: [VendorModule], + imports: [VendorModule, forwardRef(() => PayModule), SiteModule, SysModule, ScheduleModule, MemberModule], providers: [ JobsService, PaymentProcessors, diff --git a/wwjcloud/src/common/jobs/processors/payment/index.ts b/wwjcloud/src/common/jobs/processors/payment/index.ts index 5744636..9cffecb 100644 --- a/wwjcloud/src/common/jobs/processors/payment/index.ts +++ b/wwjcloud/src/common/jobs/processors/payment/index.ts @@ -20,17 +20,17 @@ export class PaymentProcessors { ? await this.corePay.findByOutTradeNo(data.siteId, data.outTradeNo) : await this.corePay.findByOutTradeNoUnsafe(data.outTradeNo); if (!pay) return { skipped: true }; - const resolved = await this.registry.resolve(pay.siteId, pay.type, pay.channel); + const resolved = await this.registry.resolve(pay.site_id, pay.type, pay.channel); const adapter: PaymentAdapter = resolved.adapter as PaymentAdapter; const config: unknown = resolved.config as unknown; const q: { status: string; tradeNo?: string } = await adapter.query( config as any, - pay.outTradeNo, + pay.out_trade_no, ); if (q.status === 'SUCCESS') { - await this.corePay.updateStatus(pay.siteId, pay.outTradeNo, 1, q.tradeNo); + await this.corePay.updateStatus(pay.site_id, pay.out_trade_no, 1, q.tradeNo); } else if (q.status === 'CLOSED') { - await this.corePay.updateStatus(pay.siteId, pay.outTradeNo, 2); + await this.corePay.updateStatus(pay.site_id, pay.out_trade_no, 2); } return { ok: true }; } diff --git a/wwjcloud/src/common/login/login.module.ts b/wwjcloud/src/common/login/login.module.ts new file mode 100644 index 0000000..e53aa7c --- /dev/null +++ b/wwjcloud/src/common/login/login.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { LoginService } from './services/admin/LoginService'; +import { LoginController } from './controllers/adminapi/LoginController'; + +@Module({ + controllers: [LoginController], + providers: [LoginService], + exports: [LoginService], +}) +export class LoginModule {} diff --git a/wwjcloud/src/common/member/entities/Member.ts b/wwjcloud/src/common/member/entities/Member.ts index c17c46c..810876c 100644 --- a/wwjcloud/src/common/member/entities/Member.ts +++ b/wwjcloud/src/common/member/entities/Member.ts @@ -5,8 +5,9 @@ import { OneToMany, ManyToOne, JoinColumn, + CreateDateColumn, + UpdateDateColumn, } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; import { MemberAccount } from './MemberAccount'; import { MemberCashOut } from './MemberCashOut'; import { MemberLabel } from './MemberLabel'; @@ -16,7 +17,7 @@ import { MemberAddress } from './MemberAddress'; import { MemberAccountLog } from './MemberAccountLog'; @Entity('member') -export class Member extends BaseEntity { +export class Member { @PrimaryGeneratedColumn({ name: 'member_id' }) member_id: number; @@ -26,6 +27,9 @@ export class Member extends BaseEntity { @Column({ name: 'pid', type: 'int', default: 0 }) pid: number; + @Column({ name: 'site_id', type: 'int', default: 0 }) + site_id: number; + @Column({ name: 'username', type: 'varchar', length: 255, default: '' }) username: string; @@ -214,6 +218,15 @@ export class Member extends BaseEntity { @Column({ name: 'remark', type: 'varchar', length: 300, default: '' }) remark: string; + @Column({ name: 'is_del', type: 'tinyint', default: 0 }) + is_del: number; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0 }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0 }) + update_time: number; + // 关联关系 @OneToMany(() => MemberAccount, (account) => account.member) accounts: MemberAccount[]; diff --git a/wwjcloud/src/common/member/entities/MemberAddress.ts b/wwjcloud/src/common/member/entities/MemberAddress.ts index b958af4..79955dd 100644 --- a/wwjcloud/src/common/member/entities/MemberAddress.ts +++ b/wwjcloud/src/common/member/entities/MemberAddress.ts @@ -5,17 +5,19 @@ import { ManyToOne, JoinColumn, } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; import { Member } from './Member'; @Entity('member_address') -export class MemberAddress extends BaseEntity { +export class MemberAddress { @PrimaryGeneratedColumn({ name: 'id' }) id: number; - @Column({ name: 'member_id', type: 'int', default: 0 }) + @Column({ name: 'member_id', type: 'int', default: 0, comment: '会员id' }) member_id: number; + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; + @Column({ name: 'name', type: 'varchar', length: 255, default: '' }) name: string; diff --git a/wwjcloud/src/common/member/entities/MemberLevel.ts b/wwjcloud/src/common/member/entities/MemberLevel.ts index d42bd08..b9b668f 100644 --- a/wwjcloud/src/common/member/entities/MemberLevel.ts +++ b/wwjcloud/src/common/member/entities/MemberLevel.ts @@ -1,50 +1,37 @@ -import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm'; -import { BaseEntity } from '@wwjCore/base/BaseEntity'; +import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn, UpdateDateColumn } from 'typeorm'; import { Member } from './Member'; @Entity('member_level') -export class MemberLevel extends BaseEntity { +export class MemberLevel { @PrimaryGeneratedColumn() level_id: number; - @Column({ type: 'varchar', length: 50, comment: '等级名称' }) + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; + + @Column({ name: 'level_name', type: 'varchar', length: 50, default: '', comment: '等级名称' }) level_name: string; - @Column({ type: 'varchar', length: 255, comment: '等级图标' }) - level_icon: string; + @Column({ name: 'growth', type: 'int', default: 0, comment: '所需成长值' }) + growth: number; - @Column({ type: 'int', default: 0, comment: '升级所需积分' }) - upgrade_point: number; + @Column({ name: 'remark', type: 'varchar', length: 255, default: '', comment: '备注' }) + remark: string; - @Column({ - type: 'decimal', - precision: 5, - scale: 2, - default: 1.0, - comment: '积分倍率', - }) - point_rate: number; - - @Column({ - type: 'decimal', - precision: 5, - scale: 2, - default: 1.0, - comment: '折扣率', - }) - discount_rate: number; - - @Column({ type: 'int', default: 0, comment: '排序' }) - sort: number; - - @Column({ type: 'tinyint', default: 1, comment: '状态 1:启用 0:禁用' }) + @Column({ name: 'status', type: 'int', default: 1, comment: '状态 0已禁用1已启用' }) status: number; - @Column({ type: 'varchar', length: 255, comment: '等级描述' }) - description: string; + @Column({ name: 'level_benefits', type: 'text', nullable: true, comment: '等级权益' }) + level_benefits: string; - @Column({ type: 'varchar', length: 255, comment: '等级权益' }) - benefits: string; + @Column({ name: 'level_gifts', type: 'text', nullable: true, comment: '等级礼包' }) + level_gifts: string; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '添加时间' }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '更新时间' }) + update_time: number; // 关联关系 @OneToMany(() => Member, (member) => member.level) diff --git a/wwjcloud/src/common/member/member.module.ts b/wwjcloud/src/common/member/member.module.ts index 6de4b20..aa89d48 100644 --- a/wwjcloud/src/common/member/member.module.ts +++ b/wwjcloud/src/common/member/member.module.ts @@ -12,6 +12,7 @@ import { MemberAccountLog } from './entities/MemberAccountLog'; import { MemberPoints } from './entities/MemberPoints'; import { MemberBalance } from './entities/MemberBalance'; import { MemberConfig } from './entities/MemberConfig'; +import { SysConfig } from '../settings/entities/sys-config.entity'; import { CoreMemberService } from './services/core/CoreMemberService'; import { MemberService as MemberApiService } from './services/api/MemberService'; import { MemberAccountService } from './services/api/MemberAccountService'; @@ -65,6 +66,7 @@ import { MemberSignController } from './controllers/adminapi/MemberSignControlle MemberPoints, MemberBalance, MemberConfig, + SysConfig, ]), ], providers: [ diff --git a/wwjcloud/src/common/member/services/core/CoreMemberAddressService.ts b/wwjcloud/src/common/member/services/core/CoreMemberAddressService.ts index b61c93c..05a7796 100644 --- a/wwjcloud/src/common/member/services/core/CoreMemberAddressService.ts +++ b/wwjcloud/src/common/member/services/core/CoreMemberAddressService.ts @@ -1,17 +1,14 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { BaseService } from '@wwjCore/base/BaseService'; import { MemberAddress } from '../../entities/MemberAddress'; @Injectable() -export class CoreMemberAddressService extends BaseService { +export class CoreMemberAddressService { constructor( @InjectRepository(MemberAddress) private memberAddressRepository: Repository, - ) { - super(memberAddressRepository); - } + ) {} /** * 获取会员地址列表 @@ -26,7 +23,7 @@ export class CoreMemberAddressService extends BaseService { where, skip: (page - 1) * limit, take: limit, - order: { is_default: 'DESC', create_time: 'DESC' }, + order: { is_default: 'DESC' }, }); } @@ -39,6 +36,33 @@ export class CoreMemberAddressService extends BaseService { }); } + /** + * 创建地址 + */ + async create(dto: any) { + const address = this.memberAddressRepository.create(dto); + return await this.memberAddressRepository.save(address); + } + + /** + * 更新地址 + */ + async update(address_id: number, dto: any) { + const result = await this.memberAddressRepository.update( + { id: address_id }, + dto + ); + return (result.affected || 0) > 0; + } + + /** + * 删除地址 + */ + async delete(address_id: number) { + const result = await this.memberAddressRepository.delete({ id: address_id }); + return (result.affected || 0) > 0; + } + /** * 设置默认地址 */ diff --git a/wwjcloud/src/common/member/services/core/CoreMemberLevelService.ts b/wwjcloud/src/common/member/services/core/CoreMemberLevelService.ts index 5c0ac05..785f090 100644 --- a/wwjcloud/src/common/member/services/core/CoreMemberLevelService.ts +++ b/wwjcloud/src/common/member/services/core/CoreMemberLevelService.ts @@ -1,17 +1,14 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { BaseService } from '@wwjCore/base/BaseService'; import { MemberLevel } from '../../entities/MemberLevel'; @Injectable() -export class CoreMemberLevelService extends BaseService { +export class CoreMemberLevelService { constructor( @InjectRepository(MemberLevel) private memberLevelRepository: Repository, - ) { - super(memberLevelRepository); - } + ) {} /** * 获取会员等级列表 @@ -24,7 +21,7 @@ export class CoreMemberLevelService extends BaseService { where, skip: (page - 1) * limit, take: limit, - order: { upgrade_point: 'ASC' }, + order: { growth: 'ASC' }, }); } @@ -37,19 +34,46 @@ export class CoreMemberLevelService extends BaseService { }); } + /** + * 创建等级 + */ + async create(dto: any) { + const level = this.memberLevelRepository.create(dto); + return await this.memberLevelRepository.save(level); + } + + /** + * 更新等级 + */ + async update(level_id: number, dto: any) { + const result = await this.memberLevelRepository.update( + { level_id }, + dto + ); + return (result.affected || 0) > 0; + } + + /** + * 删除等级 + */ + async delete(level_id: number) { + const result = await this.memberLevelRepository.delete({ level_id }); + return (result.affected || 0) > 0; + } + /** * 设置默认等级 */ async setDefault(level_id: number) { // 先取消其他等级的默认状态 await this.memberLevelRepository.update( - { sort: 0 }, - { sort: 1 } + { level_id: level_id }, + { status: 1 } ); // 设置当前等级为默认 - const result = await this.memberLevelRepository.update(level_id, { - sort: 0, + const result = await this.memberLevelRepository.update({ level_id }, { + status: 1, }); return (result.affected || 0) > 0; diff --git a/wwjcloud/src/common/member/services/core/CoreMemberService.ts b/wwjcloud/src/common/member/services/core/CoreMemberService.ts index b93de35..88defbd 100644 --- a/wwjcloud/src/common/member/services/core/CoreMemberService.ts +++ b/wwjcloud/src/common/member/services/core/CoreMemberService.ts @@ -1,21 +1,18 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, Not, Between } from 'typeorm'; -import { BaseService } from '@wwjCore/base/BaseService'; import { Member } from '../../entities/Member'; import { MemberLevel } from '../../entities/MemberLevel'; import * as bcrypt from 'bcrypt'; @Injectable() -export class CoreMemberService extends BaseService { +export class CoreMemberService { constructor( @InjectRepository(Member) private memberRepository: Repository, @InjectRepository(MemberLevel) private memberLevelRepository: Repository, - ) { - super(memberRepository); - } + ) {} /** * 创建会员 @@ -52,21 +49,28 @@ export class CoreMemberService extends BaseService { * 根据ID获取会员 */ async getMemberById(memberId: number): Promise { - return await this.findOne(memberId); + return await this.memberRepository.findOne({ + where: { member_id: memberId, is_del: 0 }, + }); } /** * 删除会员 */ async deleteMember(memberId: number): Promise { - await this.delete(memberId); + await this.memberRepository.update( + { member_id: memberId }, + { is_del: 1, update_time: Math.floor(Date.now() / 1000) }, + ); } /** * 根据ID查找会员 */ async findById(memberId: number): Promise { - const member = await this.findOne(memberId); + const member = await this.memberRepository.findOne({ + where: { member_id: memberId, is_del: 0 }, + }); if (!member) { throw new NotFoundException('会员不存在'); @@ -79,14 +83,18 @@ export class CoreMemberService extends BaseService { * 根据用户名查找会员 */ async findByUsername(username: string): Promise { - return await this.findOneBy({ username }); + return await this.memberRepository.findOne({ + where: { username, is_del: 0 }, + }); } /** * 根据手机号查找会员 */ async findByMobile(mobile: string): Promise { - return await this.findOneBy({ mobile }); + return await this.memberRepository.findOne({ + where: { mobile, is_del: 0 }, + }); } /** @@ -127,7 +135,10 @@ export class CoreMemberService extends BaseService { delete updateDto.site_id; delete updateDto.register_time; - await this.update(memberId, updateDto); + await this.memberRepository.update( + { member_id: memberId }, + { ...updateDto, update_time: Math.floor(Date.now() / 1000) }, + ); } /** diff --git a/wwjcloud/src/common/niucloud/controllers/adminapi/CloudController.ts b/wwjcloud/src/common/niucloud/controllers/adminapi/CloudController.ts index 442a8cf..0d27779 100644 --- a/wwjcloud/src/common/niucloud/controllers/adminapi/CloudController.ts +++ b/wwjcloud/src/common/niucloud/controllers/adminapi/CloudController.ts @@ -16,35 +16,30 @@ export class CloudController { @Post('build') @ApiOperation({ summary: '云编译' }) async build(@Body() body: CloudBuildDto) { - const data = await this.service.build(body); - return { code: 200, message: '编译成功', data }; + return await this.service.build(body); } @Get('buildLog') @ApiOperation({ summary: '获取云编译日志' }) async getBuildLog(@Query() query: CloudLogDto) { - const data = await this.service.getBuildLog(query); - return { code: 200, message: '获取成功', data }; + return await this.service.getBuildLog(query); } @Get('buildTask') @ApiOperation({ summary: '获取云编译任务' }) async getBuildTask() { - const data = await this.service.getBuildTask(); - return { code: 200, message: '获取成功', data }; + return await this.service.getBuildTask(); } @Post('cancelBuild') @ApiOperation({ summary: '取消云编译' }) async cancelBuild() { - const data = await this.service.cancelBuild(); - return { code: 200, message: '取消成功', data }; + return await this.service.cancelBuild(); } @Get('buildStatus') @ApiOperation({ summary: '获取编译状态' }) async getBuildStatus() { - const data = await this.service.getBuildStatus(); - return { code: 200, message: '获取成功', data }; + return await this.service.getBuildStatus(); } } diff --git a/wwjcloud/src/common/niucloud/controllers/adminapi/ModuleController.ts b/wwjcloud/src/common/niucloud/controllers/adminapi/ModuleController.ts index 87c7f94..604864b 100644 --- a/wwjcloud/src/common/niucloud/controllers/adminapi/ModuleController.ts +++ b/wwjcloud/src/common/niucloud/controllers/adminapi/ModuleController.ts @@ -16,62 +16,54 @@ export class ModuleController { @Get('page') @ApiOperation({ summary: '模块分页' }) async page(@Query() query: ModuleQueryDto) { - const data = await this.service.getPage(query); - return { code: 200, message: '获取成功', data }; + return await this.service.getPage(query); } @Get(':id') @ApiOperation({ summary: '模块详情' }) @ApiParam({ name: 'id', description: '模块ID' }) async info(@Param('id', ParseIntPipe) id: number) { - const data = await this.service.getInfo(id); - return { code: 200, message: '获取成功', data }; + return await this.service.getInfo(id); } @Post() @ApiOperation({ summary: '新增模块' }) async add(@Body() body: CreateModuleDto) { - const data = await this.service.add(body); - return { code: 200, message: '创建成功', data }; + return await this.service.add(body); } @Put(':id') @ApiOperation({ summary: '编辑模块' }) @ApiParam({ name: 'id', description: '模块ID' }) async edit(@Param('id', ParseIntPipe) id: number, @Body() body: UpdateModuleDto) { - const data = await this.service.edit(id, body); - return { code: 200, message: '更新成功', data }; + return await this.service.edit(id, body); } @Delete(':id') @ApiOperation({ summary: '删除模块' }) @ApiParam({ name: 'id', description: '模块ID' }) async delete(@Param('id', ParseIntPipe) id: number) { - const data = await this.service.delete(id); - return { code: 200, message: '删除成功', data }; + return await this.service.delete(id); } @Post(':id/install') @ApiOperation({ summary: '安装模块' }) @ApiParam({ name: 'id', description: '模块ID' }) async install(@Param('id', ParseIntPipe) id: number) { - const data = await this.service.install(id); - return { code: 200, message: '安装成功', data }; + return await this.service.install(id); } @Post(':id/uninstall') @ApiOperation({ summary: '卸载模块' }) @ApiParam({ name: 'id', description: '模块ID' }) async uninstall(@Param('id', ParseIntPipe) id: number) { - const data = await this.service.uninstall(id); - return { code: 200, message: '卸载成功', data }; + return await this.service.uninstall(id); } @Post(':id/upgrade') @ApiOperation({ summary: '升级模块' }) @ApiParam({ name: 'id', description: '模块ID' }) async upgrade(@Param('id', ParseIntPipe) id: number) { - const data = await this.service.upgrade(id); - return { code: 200, message: '升级成功', data }; + return await this.service.upgrade(id); } } diff --git a/wwjcloud/src/common/niucloud/niucloud.module.ts b/wwjcloud/src/common/niucloud/niucloud.module.ts index 3c357ca..a12f26e 100644 --- a/wwjcloud/src/common/niucloud/niucloud.module.ts +++ b/wwjcloud/src/common/niucloud/niucloud.module.ts @@ -1,4 +1,7 @@ import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Cloud } from './entities/Cloud'; +import { Module as NiucloudModuleEntity } from './entities/Module'; import { CloudController } from './controllers/adminapi/CloudController'; import { ModuleController } from './controllers/adminapi/ModuleController'; import { CloudService } from './services/admin/CloudService'; @@ -7,6 +10,7 @@ import { CoreCloudService } from './services/core/CoreCloudService'; import { CoreModuleService } from './services/core/CoreModuleService'; @Module({ + imports: [TypeOrmModule.forFeature([Cloud, NiucloudModuleEntity])], controllers: [CloudController, ModuleController], providers: [CloudService, ModuleService, CoreCloudService, CoreModuleService], exports: [CloudService, ModuleService, CoreCloudService, CoreModuleService], diff --git a/wwjcloud/src/common/notice/entities/SmsLog.ts b/wwjcloud/src/common/notice/entities/SmsLog.ts index b0c8815..76211ec 100644 --- a/wwjcloud/src/common/notice/entities/SmsLog.ts +++ b/wwjcloud/src/common/notice/entities/SmsLog.ts @@ -1,35 +1,46 @@ -import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm'; @Entity('sys_notice_sms_log') -export class SmsLog extends BaseEntity { +export class SmsLog { @PrimaryGeneratedColumn() id: number; - @Column({ name: 'mobile', type: 'varchar', length: 11, default: '' }) + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; + + @Column({ name: 'mobile', type: 'varchar', length: 11, default: '', comment: '手机号码' }) mobile: string; - @Column({ name: 'sms_type', type: 'varchar', length: 32, default: '' }) + @Column({ name: 'sms_type', type: 'varchar', length: 32, default: '', comment: '发送关键字(注册、找回密码)' }) sms_type: string; - @Column({ name: 'key', type: 'varchar', length: 32, default: '' }) + @Column({ name: 'key', type: 'varchar', length: 32, default: '', comment: '发送关键字(注册、找回密码)' }) key: string; - @Column({ name: 'template_id', type: 'varchar', length: 50, default: '' }) + @Column({ name: 'template_id', type: 'varchar', length: 50, default: '', comment: '模板ID' }) template_id: string; - @Column({ name: 'content', type: 'text' }) + @Column({ name: 'content', type: 'text', comment: '发送内容' }) content: string; - @Column({ name: 'params', type: 'text' }) - params: any; + @Column({ name: 'params', type: 'text', comment: '数据参数' }) + params: string; - @Column({ name: 'status', type: 'varchar', length: 32, default: 'sending' }) + @Column({ name: 'status', type: 'varchar', length: 32, default: 'sending', comment: '发送状态:sending-发送中;success-发送成功;fail-发送失败' }) status: string; - @Column({ name: 'result', type: 'text', nullable: true }) + @Column({ name: 'result', type: 'text', nullable: true, comment: '短信结果' }) result: string; - @Column({ name: 'send_time', type: 'int', default: 0 }) + @Column({ name: 'send_time', type: 'int', default: 0, comment: '发送时间' }) send_time: number; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '创建时间' }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '更新时间' }) + update_time: number; + + @DeleteDateColumn({ name: 'delete_time', type: 'int', default: 0, comment: '删除时间' }) + delete_time: number; } diff --git a/wwjcloud/src/common/notice/services/core/CoreSmsService.ts b/wwjcloud/src/common/notice/services/core/CoreSmsService.ts index 637808d..c5e849a 100644 --- a/wwjcloud/src/common/notice/services/core/CoreSmsService.ts +++ b/wwjcloud/src/common/notice/services/core/CoreSmsService.ts @@ -1,19 +1,16 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { BaseService } from '@wwjCore/base/BaseService'; import { SmsLog } from '../../entities/SmsLog'; import { ISmsConfig, ISmsSendParams } from '../../interfaces/sms.interface'; import { SmsStatus } from '../../enums/status.enum'; @Injectable() -export class CoreSmsService extends BaseService { +export class CoreSmsService { constructor( @InjectRepository(SmsLog) private readonly smsLogRepository: Repository, - ) { - super(smsLogRepository); - } + ) {} /** * 发送短信 @@ -30,7 +27,7 @@ export class CoreSmsService extends BaseService { try { // 创建短信日志 - savedLog = await this.create({ + savedLog = await this.smsLogRepository.save(this.smsLogRepository.create({ site_id, mobile, sms_type: 'default', @@ -39,15 +36,15 @@ export class CoreSmsService extends BaseService { template_id, params: JSON.stringify(params), status: SmsStatus.SENDING, - send_time: this.getCurrentTimestamp(), - }); + send_time: Math.floor(Date.now() / 1000), + })); // TODO: 这里应该调用实际的短信服务商API // 目前先模拟发送成功 const success = true; // 更新日志状态 - await this.update(savedLog.id, { + await this.smsLogRepository.update(savedLog.id, { status: success ? SmsStatus.SUCCESS : SmsStatus.FAILED, result: success ? '发送成功' : '发送失败', }); @@ -56,7 +53,7 @@ export class CoreSmsService extends BaseService { } catch (error) { // 记录失败日志 if (savedLog?.id) { - await this.update(savedLog.id, { + await this.smsLogRepository.update(savedLog.id, { status: SmsStatus.FAILED, result: error.message, }); @@ -85,6 +82,6 @@ export class CoreSmsService extends BaseService { */ async getSmsLogs(site_id: number, where: any = {}): Promise { const query = { site_id, ...where }; - return await this.findMany(query); + return await this.smsLogRepository.find({ where: query }); } } diff --git a/wwjcloud/src/common/pay/controllers/admin/PayChannelController.ts b/wwjcloud/src/common/pay/controllers/admin/PayChannelController.ts index 1332f1e..6d9f720 100644 --- a/wwjcloud/src/common/pay/controllers/admin/PayChannelController.ts +++ b/wwjcloud/src/common/pay/controllers/admin/PayChannelController.ts @@ -9,6 +9,7 @@ Query, UseGuards, Req, + UnauthorizedException, } from "@nestjs/common"; import { ApiTags, @@ -43,19 +44,19 @@ export class PayChannelController { constructor(private readonly payChannelService: PayChannelService) {} @Get("list") + @Roles('admin') @ApiOperation({ summary: "获取支付渠道列表" }) @ApiResponse({ status: 200, description: "获取成功" }) async getChannelList(@Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payChannelService.getChannelList(siteId); - return { code: 200, message: "获取成功", data: result }; - } catch (error) { - return { code: 500, message: "获取失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + return await this.payChannelService.getChannelList(siteId); } @Get(":type/:channel") + @Roles('admin') @ApiOperation({ summary: "获取支付渠道配置" }) @ApiParam({ name: "type", description: "支付方式" }) @ApiParam({ name: "channel", description: "支付渠道" }) @@ -65,16 +66,15 @@ export class PayChannelController { @Param("channel") channel: string, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payChannelService.getConfig(siteId, type, channel); - return { code: 200, message: "获取成功", data: result }; - } catch (error) { - return { code: 500, message: "获取失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + return await this.payChannelService.getConfig(siteId, type, channel); } @Post(":type/:channel") + @Roles('admin') @ApiOperation({ summary: "设置支付渠道配置" }) @ApiParam({ name: "type", description: "支付方式" }) @ApiParam({ name: "channel", description: "支付渠道" }) @@ -85,16 +85,16 @@ export class PayChannelController { @Body() createPayChannelDto: CreatePayChannelDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payChannelService.set(siteId, channel, type, createPayChannelDto); - return { code: 200, message: "设置成功", data: result }; - } catch (error) { - return { code: 500, message: "设置失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + const result = await this.payChannelService.set(siteId, channel, type, createPayChannelDto); + return { success: true, message: '设置成功' }; } @Put(":type/:channel") + @Roles('admin') @ApiOperation({ summary: "更新支付渠道配置" }) @ApiParam({ name: "type", description: "支付方式" }) @ApiParam({ name: "channel", description: "支付渠道" }) @@ -105,16 +105,16 @@ export class PayChannelController { @Body() updatePayChannelDto: UpdatePayChannelDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payChannelService.set(siteId, channel, type, updatePayChannelDto); - return { code: 200, message: "更新成功", data: result }; - } catch (error) { - return { code: 500, message: "更新失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + const result = await this.payChannelService.set(siteId, channel, type, updatePayChannelDto); + return { success: true, message: '更新成功' }; } @Delete(":type/:channel") + @Roles('admin') @ApiOperation({ summary: "删除支付渠道配置" }) @ApiParam({ name: "type", description: "支付方式" }) @ApiParam({ name: "channel", description: "支付渠道" }) @@ -124,16 +124,16 @@ export class PayChannelController { @Param("channel") channel: string, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payChannelService.delete(siteId, type, channel); - return { code: 200, message: "删除成功", data: result }; - } catch (error) { - return { code: 500, message: "删除失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + const result = await this.payChannelService.delete(siteId, type, channel); + return { success: true, message: '删除成功' }; } @Put(":type/:channel/status") + @Roles('admin') @ApiOperation({ summary: "更新支付渠道状态" }) @ApiParam({ name: "type", description: "支付方式" }) @ApiParam({ name: "channel", description: "支付渠道" }) @@ -144,12 +144,11 @@ export class PayChannelController { @Body() body: { status: number }, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payChannelService.updateStatus(siteId, type, channel, body.status); - return { code: 200, message: "更新成功", data: result }; - } catch (error) { - return { code: 500, message: "更新失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + const result = await this.payChannelService.updateStatus(siteId, type, channel, body.status); + return { success: true, message: '更新成功' }; } } diff --git a/wwjcloud/src/common/pay/controllers/admin/PayController.ts b/wwjcloud/src/common/pay/controllers/admin/PayController.ts index c9be403..d58c883 100644 --- a/wwjcloud/src/common/pay/controllers/admin/PayController.ts +++ b/wwjcloud/src/common/pay/controllers/admin/PayController.ts @@ -7,6 +7,8 @@ Query, UseGuards, Req, + UnauthorizedException, + NotFoundException, } from "@nestjs/common"; import { ApiTags, @@ -42,77 +44,76 @@ export class PayController { constructor(private readonly payService: PayService) {} @Get("audit/page") + @Roles('admin') @ApiOperation({ summary: "获取待审核支付记录" }) @ApiResponse({ status: 200, description: "获取成功" }) async getAuditPage(@Query() query: PayAuditQueryDto, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payService.getAuditPage(siteId, query); - return { code: 200, message: "获取成功", data: result }; - } catch (error) { - return { code: 500, message: "获取失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + return await this.payService.getAuditPage(siteId, query); } @Get(":id") + @Roles('admin') @ApiOperation({ summary: "获取支付详情" }) @ApiParam({ name: "id", description: "支付ID" }) @ApiResponse({ status: 200, description: "获取成功" }) async getDetail(@Param("id") id: number, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payService.getDetail(siteId, id); - if (!result) { - return { code: 404, message: "支付记录不存在" }; - } - return { code: 200, message: "获取成功", data: result }; - } catch (error) { - return { code: 500, message: "获取失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + const result = await this.payService.getDetail(siteId, id); + if (!result) { + throw new NotFoundException('支付记录不存在'); + } + return result; } @Post("pass") + @Roles('admin') @ApiOperation({ summary: "支付审核通过" }) @ApiResponse({ status: 200, description: "审核成功" }) async pass(@Body() payPassDto: PayPassDto, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payService.pass(siteId, payPassDto.outTradeNo); - if (!result) { - return { code: 404, message: "支付记录不存在" }; - } - return { code: 200, message: "审核通过成功" }; - } catch (error) { - return { code: 500, message: "审核失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + const result = await this.payService.pass(siteId, payPassDto.outTradeNo); + if (!result) { + throw new NotFoundException('支付记录不存在'); + } + return { success: true, message: '审核通过成功' }; } @Post("refuse") + @Roles('admin') @ApiOperation({ summary: "支付审核拒绝" }) @ApiResponse({ status: 200, description: "审核成功" }) async refuse(@Body() payRefuseDto: PayRefuseDto, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payService.refuse(siteId, payRefuseDto.outTradeNo, payRefuseDto.reason); - if (!result) { - return { code: 404, message: "支付记录不存在" }; - } - return { code: 200, message: "审核拒绝成功" }; - } catch (error) { - return { code: 500, message: "审核失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + const result = await this.payService.refuse(siteId, payRefuseDto.outTradeNo, payRefuseDto.reason); + if (!result) { + throw new NotFoundException('支付记录不存在'); + } + return { success: true, message: '审核拒绝成功' }; } @Get("count") + @Roles('admin') @ApiOperation({ summary: "统计支付数据" }) @ApiResponse({ status: 200, description: "获取成功" }) async payCount(@Query() query: any, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payService.payCount(siteId, query); - return { code: 200, message: "获取成功", data: { count: result } }; - } catch (error) { - return { code: 500, message: "获取失败", error: error.message }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); } + const result = await this.payService.payCount(siteId, query); + return { count: result }; } } diff --git a/wwjcloud/src/common/pay/controllers/admin/PayTemplateController.ts b/wwjcloud/src/common/pay/controllers/admin/PayTemplateController.ts deleted file mode 100644 index ea0f1a5..0000000 --- a/wwjcloud/src/common/pay/controllers/admin/PayTemplateController.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Body, Controller, Post, Get, Query, Req, UseGuards } from '@nestjs/common'; -import { ApiOperation, ApiTags, ApiResponse } from '@nestjs/swagger'; -import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; -import { RolesGuard } from '../../../auth/guards/RolesGuard'; -import { CreatePayTemplateDto } from '../../dto/admin/CreatePayTemplateDto'; -import { UpdatePayTemplateDto } from '../../dto/admin/UpdatePayTemplateDto'; -import { PayTemplateService } from '../../services/admin/PayTemplateService'; - -interface AuthenticatedRequest extends Request { - user?: { - siteId?: number; - uid?: number; - }; -} - -/** - * 支付模板控制器 - Admin层 - * 对应PHP: 支付模板相关控制器 - */ -@ApiTags('支付模板') -@Controller('adminapi/pay/template') -@UseGuards(JwtAuthGuard, RolesGuard) -export class PayTemplateController { - constructor(private readonly payTemplateService: PayTemplateService) {} - - @Post('create') - @ApiOperation({ summary: '创建支付模板' }) - @ApiResponse({ status: 200, description: '创建成功' }) - async create(@Body() createPayTemplateDto: CreatePayTemplateDto, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payTemplateService.create(siteId, createPayTemplateDto); - return { code: 200, message: '创建成功', data: result }; - } catch (error) { - return { code: 500, message: '创建失败', error: error.message }; - } - } - - @Post('update') - @ApiOperation({ summary: '更新支付模板' }) - @ApiResponse({ status: 200, description: '更新成功' }) - async update(@Body() updatePayTemplateDto: UpdatePayTemplateDto, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const id = updatePayTemplateDto['id']; - if (!id) { - return { code: 400, message: '缺少ID参数' }; - } - const result = await this.payTemplateService.update(siteId, id, updatePayTemplateDto); - return { code: 200, message: '更新成功', data: result }; - } catch (error) { - return { code: 500, message: '更新失败', error: error.message }; - } - } - - @Get('detail') - @ApiOperation({ summary: '获取支付模板详情' }) - @ApiResponse({ status: 200, description: '获取成功' }) - async detail(@Query('id') id: number, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payTemplateService.getDetail(siteId, id); - if (!result) { - return { code: 404, message: '支付模板不存在' }; - } - return { code: 200, message: '获取成功', data: result }; - } catch (error) { - return { code: 500, message: '获取失败', error: error.message }; - } - } - - @Get('list') - @ApiOperation({ summary: '获取支付模板列表' }) - @ApiResponse({ status: 200, description: '获取成功' }) - async list(@Query() query: any, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payTemplateService.getList(siteId, query); - return { code: 200, message: '获取成功', data: result }; - } catch (error) { - return { code: 500, message: '获取失败', error: error.message }; - } - } - - @Post('delete') - @ApiOperation({ summary: '删除支付模板' }) - @ApiResponse({ status: 200, description: '删除成功' }) - async delete(@Body('id') id: number, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.payTemplateService.delete(siteId, id); - if (!result) { - return { code: 404, message: '支付模板不存在' }; - } - return { code: 200, message: '删除成功' }; - } catch (error) { - return { code: 500, message: '删除失败', error: error.message }; - } - } -} \ No newline at end of file diff --git a/wwjcloud/src/common/pay/controllers/adminapi/PayRefundController.ts b/wwjcloud/src/common/pay/controllers/adminapi/PayRefundController.ts index a3f2765..2035e3f 100644 --- a/wwjcloud/src/common/pay/controllers/adminapi/PayRefundController.ts +++ b/wwjcloud/src/common/pay/controllers/adminapi/PayRefundController.ts @@ -8,6 +8,7 @@ import { Query, UseGuards, } from '@nestjs/common'; +import { Roles } from '../../../auth/decorators/RolesDecorator'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; import { RolesGuard } from '../../../auth/guards/RolesGuard'; import { PayRefundService } from '../../services/admin/PayRefundService'; @@ -21,6 +22,7 @@ export class PayRefundController { * 退款列表 */ @Get('lists') + @Roles('admin') async lists(@Query() query: any) { return this.payRefundService.getPage(query); } @@ -29,6 +31,7 @@ export class PayRefundController { * 退款信息 */ @Get('info/:refund_id') + @Roles('admin') async info(@Param('refund_id') refund_id: string) { return this.payRefundService.getInfo(parseInt(refund_id)); } @@ -37,6 +40,7 @@ export class PayRefundController { * 创建退款 */ @Post('create') + @Roles('admin') async create(@Body() data: { pay_id: number; refund_amount: number; @@ -51,6 +55,7 @@ export class PayRefundController { * 处理退款 */ @Post('process/:refund_id') + @Roles('admin') async process(@Param('refund_id') refund_id: string) { return this.payRefundService.process(parseInt(refund_id)); } @@ -59,6 +64,7 @@ export class PayRefundController { * 取消退款 */ @Post('cancel/:refund_id') + @Roles('admin') async cancel(@Param('refund_id') refund_id: string) { return this.payRefundService.cancel(parseInt(refund_id)); } @@ -67,6 +73,7 @@ export class PayRefundController { * 获取退款状态 */ @Get('status/:refund_id') + @Roles('admin') async getStatus(@Param('refund_id') refund_id: string) { return this.payRefundService.getStatus(parseInt(refund_id)); } @@ -75,6 +82,7 @@ export class PayRefundController { * 获取退款统计 */ @Get('statistics') + @Roles('admin') async getStatistics(@Query() query: any) { return this.payRefundService.getStatistics(query); } diff --git a/wwjcloud/src/common/pay/controllers/adminapi/TransferController.ts b/wwjcloud/src/common/pay/controllers/adminapi/TransferController.ts index b1c6c88..db13d63 100644 --- a/wwjcloud/src/common/pay/controllers/adminapi/TransferController.ts +++ b/wwjcloud/src/common/pay/controllers/adminapi/TransferController.ts @@ -8,6 +8,7 @@ import { Query, UseGuards, } from '@nestjs/common'; +import { Roles } from '../../../auth/decorators/RolesDecorator'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; import { RolesGuard } from '../../../auth/guards/RolesGuard'; import { TransferService } from '../../services/admin/TransferService'; @@ -21,6 +22,7 @@ export class TransferController { * 转账列表 */ @Get('lists') + @Roles('admin') async lists(@Query() query: any) { return this.transferService.getPage(query); } @@ -29,6 +31,7 @@ export class TransferController { * 转账信息 */ @Get('info/:transfer_id') + @Roles('admin') async info(@Param('transfer_id') transfer_id: string) { return this.transferService.getInfo(parseInt(transfer_id)); } @@ -37,6 +40,7 @@ export class TransferController { * 创建转账 */ @Post('create') + @Roles('admin') async create(@Body() data: { transfer_type: string; transfer_amount: number; @@ -52,6 +56,7 @@ export class TransferController { * 处理转账 */ @Post('process/:transfer_id') + @Roles('admin') async process(@Param('transfer_id') transfer_id: string) { return this.transferService.process(parseInt(transfer_id)); } @@ -60,6 +65,7 @@ export class TransferController { * 取消转账 */ @Post('cancel/:transfer_id') + @Roles('admin') async cancel(@Param('transfer_id') transfer_id: string) { return this.transferService.cancel(parseInt(transfer_id)); } @@ -68,6 +74,7 @@ export class TransferController { * 获取转账状态 */ @Get('status/:transfer_id') + @Roles('admin') async getStatus(@Param('transfer_id') transfer_id: string) { return this.transferService.getStatus(parseInt(transfer_id)); } @@ -76,6 +83,7 @@ export class TransferController { * 获取转账统计 */ @Get('statistics') + @Roles('admin') async getStatistics(@Query() query: any) { return this.transferService.getStatistics(query); } diff --git a/wwjcloud/src/common/pay/dto/admin/CreatePayTemplateDto.ts b/wwjcloud/src/common/pay/dto/admin/CreatePayTemplateDto.ts deleted file mode 100644 index e4853d9..0000000 --- a/wwjcloud/src/common/pay/dto/admin/CreatePayTemplateDto.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { IsString, IsOptional, IsEnum, ValidateIf } from 'class-validator'; -import { Transform } from 'class-transformer'; - -/** - * 支付方式枚举 - * 对应PHP: app\dict\pay\PayDict - */ -export enum PayType { - WECHATPAY = 'wechatpay', - ALIPAY = 'alipay', -} - -/** - * 创建支付模板DTO - * 对应PHP: app\validate\pay\PayTemplate 的 add 场景 - */ -export class CreatePayTemplateDto { - @ApiProperty({ description: '模板名称', example: '微信支付' }) - @IsString() - name: string; - - @ApiProperty({ description: '支付方式', enum: PayType, example: PayType.WECHATPAY }) - @IsEnum(PayType, { message: '不存在的支付方式' }) - type: PayType; - - // 支付宝相关字段 - 仅当type为ALIPAY时必填 - @ApiPropertyOptional({ description: '支付宝AppID', example: '2021000000000000' }) - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝AppID必填' }) - app_id?: string; - - @ApiPropertyOptional({ description: '支付宝应用私钥证书' }) - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝应用私钥证书必填' }) - app_secret_cert?: string; - - @ApiPropertyOptional({ description: '支付宝应用公钥证书路径' }) - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝应用公钥证书路径必填' }) - app_public_cert_path?: string; - - @ApiPropertyOptional({ description: '支付宝公钥证书路径' }) - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝公钥证书路径必填' }) - alipay_public_cert_path?: string; - - @ApiPropertyOptional({ description: '支付宝根证书路径' }) - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝根证书路径必填' }) - alipay_root_cert_path?: string; - - // 微信支付相关字段 - 仅当type为WECHATPAY时必填 - @ApiPropertyOptional({ description: '微信商户号', example: '1900000109' }) - @ValidateIf(o => o.type === PayType.WECHATPAY) - @IsString({ message: '微信商户号必填' }) - mch_id?: string; - - @ApiPropertyOptional({ description: '微信商户API密钥' }) - @ValidateIf(o => o.type === PayType.WECHATPAY) - @IsString({ message: '微信商户API密钥必填' }) - mch_secret_key?: string; - - @ApiPropertyOptional({ description: '微信商户私钥证书' }) - @ValidateIf(o => o.type === PayType.WECHATPAY) - @IsString({ message: '微信商户私钥证书必填' }) - mch_secret_cert?: string; - - @ApiPropertyOptional({ description: '微信商户公钥证书路径' }) - @ValidateIf(o => o.type === PayType.WECHATPAY) - @IsString({ message: '微信商户公钥证书路径必填' }) - mch_public_cert_path?: string; -} \ No newline at end of file diff --git a/wwjcloud/src/common/pay/dto/admin/UpdatePayTemplateDto.ts b/wwjcloud/src/common/pay/dto/admin/UpdatePayTemplateDto.ts deleted file mode 100644 index 26cd929..0000000 --- a/wwjcloud/src/common/pay/dto/admin/UpdatePayTemplateDto.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { IsString, IsOptional, IsEnum, ValidateIf, IsNumber } from 'class-validator'; -import { Transform } from 'class-transformer'; -import { PayType } from './CreatePayTemplateDto'; - -/** - * 更新支付模板DTO - * 对应PHP: app\validate\pay\PayTemplate 的 edit 场景 - */ -export class UpdatePayTemplateDto { - @ApiProperty({ description: '支付模板ID', example: 1 }) - @IsNumber({}, { message: '支付模板ID必须是数字' }) - id: number; - @ApiProperty({ description: '模板名称', example: '微信支付' }) - @IsString() - name: string; - - @ApiPropertyOptional({ description: '支付方式', enum: PayType, example: PayType.WECHATPAY }) - @IsOptional() - @IsEnum(PayType, { message: '不存在的支付方式' }) - type?: PayType; - - // 支付宝相关字段 - 仅当type为ALIPAY时必填 - @ApiPropertyOptional({ description: '支付宝AppID', example: '2021000000000000' }) - @IsOptional() - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝AppID必填' }) - app_id?: string; - - @ApiPropertyOptional({ description: '支付宝应用私钥证书' }) - @IsOptional() - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝应用私钥证书必填' }) - app_secret_cert?: string; - - @ApiPropertyOptional({ description: '支付宝应用公钥证书路径' }) - @IsOptional() - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝应用公钥证书路径必填' }) - app_public_cert_path?: string; - - @ApiPropertyOptional({ description: '支付宝公钥证书路径' }) - @IsOptional() - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝公钥证书路径必填' }) - alipay_public_cert_path?: string; - - @ApiPropertyOptional({ description: '支付宝根证书路径' }) - @IsOptional() - @ValidateIf(o => o.type === PayType.ALIPAY) - @IsString({ message: '支付宝根证书路径必填' }) - alipay_root_cert_path?: string; - - // 微信支付相关字段 - 仅当type为WECHATPAY时必填 - @ApiPropertyOptional({ description: '微信商户号', example: '1900000109' }) - @IsOptional() - @ValidateIf(o => o.type === PayType.WECHATPAY) - @IsString({ message: '微信商户号必填' }) - mch_id?: string; - - @ApiPropertyOptional({ description: '微信商户API密钥' }) - @IsOptional() - @ValidateIf(o => o.type === PayType.WECHATPAY) - @IsString({ message: '微信商户API密钥必填' }) - mch_secret_key?: string; - - @ApiPropertyOptional({ description: '微信商户私钥证书' }) - @IsOptional() - @ValidateIf(o => o.type === PayType.WECHATPAY) - @IsString({ message: '微信商户私钥证书必填' }) - mch_secret_cert?: string; - - @ApiPropertyOptional({ description: '微信商户公钥证书路径' }) - @IsOptional() - @ValidateIf(o => o.type === PayType.WECHATPAY) - @IsString({ message: '微信商户公钥证书路径必填' }) - mch_public_cert_path?: string; -} \ No newline at end of file diff --git a/wwjcloud/src/common/pay/dto/admin/index.ts b/wwjcloud/src/common/pay/dto/admin/index.ts deleted file mode 100644 index 1ea7017..0000000 --- a/wwjcloud/src/common/pay/dto/admin/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './CreatePayTemplateDto'; -export * from './UpdatePayTemplateDto'; \ No newline at end of file diff --git a/wwjcloud/src/common/pay/entities/Pay.ts b/wwjcloud/src/common/pay/entities/Pay.ts index bbb0c88..9cd1ad5 100644 --- a/wwjcloud/src/common/pay/entities/Pay.ts +++ b/wwjcloud/src/common/pay/entities/Pay.ts @@ -1,60 +1,71 @@ import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from "typeorm"; -import { BaseEntity } from "../../../core/base/BaseEntity"; /** * 支付实体 * 对应PHP: app\model\pay\Pay */ @Entity("pay") -export class Pay extends BaseEntity { +export class Pay { @PrimaryGeneratedColumn() id: number; - @Column({ name: "site_id", type: "int", comment: "站点ID" }) - siteId: number; + @Column({ name: "site_id", type: "int", default: 0, comment: "站点id" }) + site_id: number; - @Column({ name: "out_trade_no", length: 100, comment: "商户订单号" }) - outTradeNo: string; + @Column({ name: "main_id", type: "int", default: 0, comment: "支付会员id" }) + main_id: number; - @Column({ name: "trade_type", length: 50, comment: "交易类型" }) - tradeType: string; + @Column({ name: "from_main_id", type: "int", default: 0, comment: "发起支付会员id" }) + from_main_id: number; - @Column({ name: "trade_id", type: "int", default: 0, comment: "交易ID" }) - tradeId: number; + @Column({ name: "out_trade_no", type: "varchar", length: 255, default: "", comment: "支付流水号" }) + out_trade_no: string; - @Column({ name: "trade_no", length: 100, default: "", comment: "交易流水号" }) - tradeNo: string; + @Column({ name: "trade_type", type: "varchar", length: 255, default: "", comment: "业务类型" }) + trade_type: string; - @Column({ name: "body", length: 500, comment: "商品描述" }) + @Column({ name: "trade_id", type: "int", default: 0, comment: "业务id" }) + trade_id: number; + + @Column({ name: "trade_no", type: "varchar", length: 255, default: "", comment: "交易单号" }) + trade_no: string; + + @Column({ name: "body", type: "varchar", length: 1000, default: "", comment: "支付主体" }) body: string; - @Column({ name: "money", type: "decimal", precision: 10, scale: 2, comment: "支付金额" }) + @Column({ name: "money", type: "decimal", precision: 10, scale: 2, default: 0.00, comment: "支付金额" }) money: number; - @Column({ name: "voucher", length: 500, default: "", comment: "支付凭证" }) + @Column({ name: "voucher", type: "varchar", length: 255, default: "", comment: "支付票据" }) voucher: string; - @Column({ name: "status", type: "tinyint", default: 0, comment: "支付状态 0待支付 1已支付 2已关闭 3已退款" }) + @Column({ name: "status", type: "int", default: 0, comment: "支付状态(0.待支付 1. 支付中 2. 已支付 -1已取消)" }) status: number; - @Column({ name: "type", length: 50, comment: "支付方式" }) + @Column({ name: "json", type: "varchar", length: 255, default: "", comment: "支付扩展用支付信息" }) + json: string; + + @CreateDateColumn({ name: "create_time", type: "int", default: 0, comment: "创建时间" }) + create_time: number; + + @Column({ name: "pay_time", type: "int", default: 0, comment: "支付时间" }) + pay_time: number; + + @Column({ name: "type", type: "varchar", length: 255, default: "", comment: "支付方式" }) type: string; - @Column({ name: "channel", length: 50, comment: "支付渠道" }) + @Column({ name: "channel", type: "varchar", length: 50, default: "", comment: "支付渠道" }) channel: string; - @Column({ name: "fail_reason", length: 500, default: "", comment: "失败原因" }) - failReason: string; + @Column({ name: "fail_reason", type: "varchar", length: 255, default: "", comment: "失败原因" }) + fail_reason: string; - @Column({ name: "allow_type", type: "json", nullable: true, comment: "允许的支付方式" }) - allowType: string[]; + @Column({ name: "close_time", type: "int", default: 0, comment: "关闭时间" }) + close_time: number; - @Column({ name: "pay_time", type: "timestamp", nullable: true, comment: "支付时间" }) - payTime: Date; + @Column({ name: "is_del", type: "tinyint", default: 0, comment: "是否删除" }) + is_del: number; - @Column({ name: "close_time", type: "timestamp", nullable: true, comment: "关闭时间" }) - closeTime: Date; - - @CreateDateColumn({ name: "create_time", comment: "创建时间" }) - createTime: Date; + @UpdateDateColumn({ name: "update_time", type: "int", default: 0, comment: "更新时间" }) + update_time: number; } diff --git a/wwjcloud/src/common/pay/entities/PayTemplate.ts b/wwjcloud/src/common/pay/entities/PayTemplate.ts deleted file mode 100644 index 81e2a54..0000000 --- a/wwjcloud/src/common/pay/entities/PayTemplate.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; - -/** - * 支付模板实体 - * 对应PHP: 支付模板相关数据表 - */ -@Entity('pay_template') -export class PayTemplate extends BaseEntity { - @PrimaryGeneratedColumn({ name: 'id' }) - id: number; - - - @Column({ name: 'name', type: 'varchar', length: 50, comment: '模板名称' }) - name: string; - - @Column({ name: 'type', type: 'varchar', length: 50, comment: '支付方式' }) - type: string; - - // 支付宝相关字段 - @Column({ name: 'app_id', type: 'varchar', length: 255, nullable: true, comment: '支付宝AppID' }) - app_id: string | null; - - @Column({ name: 'app_secret_cert', type: 'text', nullable: true, comment: '支付宝应用私钥证书' }) - app_secret_cert: string | null; - - @Column({ name: 'app_public_cert_path', type: 'varchar', length: 255, nullable: true, comment: '支付宝应用公钥证书路径' }) - app_public_cert_path: string | null; - - @Column({ name: 'alipay_public_cert_path', type: 'varchar', length: 255, nullable: true, comment: '支付宝公钥证书路径' }) - alipay_public_cert_path: string | null; - - @Column({ name: 'alipay_root_cert_path', type: 'varchar', length: 255, nullable: true, comment: '支付宝根证书路径' }) - alipay_root_cert_path: string | null; - - // 微信支付相关字段 - @Column({ name: 'mch_id', type: 'varchar', length: 255, nullable: true, comment: '微信商户号' }) - mch_id: string | null; - - @Column({ name: 'mch_secret_key', type: 'varchar', length: 255, nullable: true, comment: '微信商户API密钥' }) - mch_secret_key: string | null; - - @Column({ name: 'mch_secret_cert', type: 'text', nullable: true, comment: '微信商户私钥证书' }) - mch_secret_cert: string | null; - - @Column({ name: 'mch_public_cert_path', type: 'varchar', length: 255, nullable: true, comment: '微信商户公钥证书路径' }) - mch_public_cert_path: string | null; - - // site_id/create_time/update_time 由 BaseEntity 提供 -} \ No newline at end of file diff --git a/wwjcloud/src/common/pay/pay.module.ts b/wwjcloud/src/common/pay/pay.module.ts index 592a560..298de00 100644 --- a/wwjcloud/src/common/pay/pay.module.ts +++ b/wwjcloud/src/common/pay/pay.module.ts @@ -1,8 +1,7 @@ -import { Module } from "@nestjs/common"; +import { Module, forwardRef } from "@nestjs/common"; import { TypeOrmModule } from "@nestjs/typeorm"; import { Pay } from "./entities/Pay"; import { PayChannel } from "./entities/PayChannel"; -import { PayTemplate } from "./entities/PayTemplate"; import { PayRefund } from "./entities/PayRefund"; import { PayTransfer } from "./entities/PayTransfer"; @@ -15,7 +14,6 @@ import { CorePayTransferService } from "./services/core/CorePayTransferService"; // Admin Services import { PayService } from "./services/admin/PayService"; import { PayChannelService } from "./services/admin/PayChannelService"; -import { PayTemplateService } from "./services/admin/PayTemplateService"; import { PayApiService } from "./services/api/PayApiService"; import { TransferApiService } from "./services/api/TransferApiService"; import { PayRefundService } from "./services/admin/PayRefundService"; @@ -24,12 +22,13 @@ import { TransferService } from "./services/admin/TransferService"; // Admin Controllers import { PayController } from "./controllers/admin/PayController"; import { PayChannelController } from "./controllers/admin/PayChannelController"; -import { PayTemplateController } from "./controllers/admin/PayTemplateController"; import { PayApiController } from "./controllers/api/PayApiController"; import { TransferApiController } from "./controllers/api/TransferApiController"; import { PayRefundController } from "./controllers/adminapi/PayRefundController"; import { TransferController } from "./controllers/adminapi/TransferController"; import { JobsModule } from "../../common/jobs/jobs.module"; +import { VendorModule } from "../../vendor"; +import { PaymentAdapterRegistry } from "../../vendor/pay/providers/payment.provider"; import { PaymentEventHandlers } from "./subscribers/paymentEventHandlers"; /** @@ -38,8 +37,9 @@ import { PaymentEventHandlers } from "./subscribers/paymentEventHandlers"; */ @Module({ imports: [ - TypeOrmModule.forFeature([Pay, PayChannel, PayTemplate, PayRefund, PayTransfer]), - JobsModule, + TypeOrmModule.forFeature([Pay, PayChannel, PayRefund, PayTransfer]), + forwardRef(() => JobsModule), + VendorModule, ], providers: [ // Core Services @@ -51,18 +51,17 @@ import { PaymentEventHandlers } from "./subscribers/paymentEventHandlers"; // Admin Services PayService, PayChannelService, - PayTemplateService, PayRefundService, TransferService, PayApiService, TransferApiService, PaymentEventHandlers, + PaymentAdapterRegistry, ], controllers: [ // Admin Controllers PayController, PayChannelController, - PayTemplateController, PayApiController, TransferApiController, PayRefundController, @@ -84,6 +83,7 @@ import { PaymentEventHandlers } from "./subscribers/paymentEventHandlers"; // Api Services PayApiService, TransferApiService, + PaymentAdapterRegistry, ], }) export class PayModule {} diff --git a/wwjcloud/src/common/pay/services/admin/PayTemplateService.ts b/wwjcloud/src/common/pay/services/admin/PayTemplateService.ts deleted file mode 100644 index 1878332..0000000 --- a/wwjcloud/src/common/pay/services/admin/PayTemplateService.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; -import { PayTemplate } from '../../entities/PayTemplate'; -import { CreatePayTemplateDto, PayType } from '../../dto/admin/CreatePayTemplateDto'; -import { UpdatePayTemplateDto } from '../../dto/admin/UpdatePayTemplateDto'; - -/** - * 支付模板服务 - Admin层 - * 对应PHP: 支付模板相关服务 - */ -@Injectable() -export class PayTemplateService { - constructor( - @InjectRepository(PayTemplate) - private readonly payTemplateRepository: Repository, - ) {} - - /** - * 创建支付模板 - * @param siteId 站点ID - * @param createPayTemplateDto 创建支付模板DTO - * @returns 创建的支付模板 - */ - async create(siteId: number, createPayTemplateDto: CreatePayTemplateDto) { - const payTemplate = this.payTemplateRepository.create({ - site_id: siteId, - ...createPayTemplateDto, - create_time: Math.floor(Date.now() / 1000), - }); - - return await this.payTemplateRepository.save(payTemplate); - } - - /** - * 更新支付模板 - * @param siteId 站点ID - * @param id 支付模板ID - * @param updatePayTemplateDto 更新支付模板DTO - * @returns 更新后的支付模板 - */ - async update(siteId: number, id: number, updatePayTemplateDto: UpdatePayTemplateDto) { - const payTemplate = await this.payTemplateRepository.findOne({ - where: { id, site_id: siteId }, - }); - - if (!payTemplate) { - throw new Error('支付模板不存在'); - } - - // 更新字段 - Object.assign(payTemplate, updatePayTemplateDto, { - update_time: Math.floor(Date.now() / 1000), - }); - - return await this.payTemplateRepository.save(payTemplate); - } - - /** - * 获取支付模板详情 - * @param siteId 站点ID - * @param id 支付模板ID - * @returns 支付模板详情 - */ - async getDetail(siteId: number, id: number) { - return await this.payTemplateRepository.findOne({ - where: { id, site_id: siteId }, - }); - } - - /** - * 获取支付模板列表 - * @param siteId 站点ID - * @param query 查询参数 - * @returns 支付模板列表 - */ - async getList(siteId: number, query: any) { - const queryBuilder = this.payTemplateRepository.createQueryBuilder('pay_template') - .where('pay_template.site_id = :siteId', { siteId }); - - // 按名称搜索 - if (query.name) { - queryBuilder.andWhere('pay_template.name LIKE :name', { name: `%${query.name}%` }); - } - - // 按支付方式筛选 - if (query.type) { - queryBuilder.andWhere('pay_template.type = :type', { type: query.type }); - } - - // 分页 - const page = query.page || 1; - const pageSize = query.page_size || 10; - const skip = (page - 1) * pageSize; - - queryBuilder.orderBy('pay_template.create_time', 'DESC') - .skip(skip) - .take(pageSize); - - const [list, total] = await queryBuilder.getManyAndCount(); - - return { - list, - page_info: { - page, - page_size: pageSize, - count: total, - page_count: Math.ceil(total / pageSize), - }, - }; - } - - /** - * 删除支付模板 - * @param siteId 站点ID - * @param id 支付模板ID - * @returns 是否成功 - */ - async delete(siteId: number, id: number) { - const result = await this.payTemplateRepository.delete({ - id, - site_id: siteId, - }); - - return (result.affected || 0) > 0; - } -} \ No newline at end of file diff --git a/wwjcloud/src/common/pay/services/api/PayApiService.ts b/wwjcloud/src/common/pay/services/api/PayApiService.ts index 3f1e8b1..c3fa511 100644 --- a/wwjcloud/src/common/pay/services/api/PayApiService.ts +++ b/wwjcloud/src/common/pay/services/api/PayApiService.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@nestjs/common"; +import { Injectable, UnauthorizedException } from "@nestjs/common"; import { CorePayService } from "../core/CorePayService"; import { CorePayChannelService } from "../core/CorePayChannelService"; import { CreatePayDto, RefundDto } from "../../dto/PayDto"; @@ -83,17 +83,17 @@ export class PayApiService { return existed; } const created = await this.corePayService.add({ - siteId, - outTradeNo: dto.outTradeNo, - tradeType: dto.tradeType, - tradeId: dto.tradeId, + site_id: siteId, + out_trade_no: dto.outTradeNo, + trade_type: dto.tradeType, + trade_id: dto.tradeId, body: dto.body, money: dto.money as any, voucher: dto.voucher || "", status: 0, type: dto.type, channel: dto.channel, - allowType: dto.allowType || undefined, + // allowType: dto.allowType || undefined, // 字段不存在,注释掉 }); const gatewayResp = await adapter.create(config, { outTradeNo: dto.outTradeNo, @@ -111,7 +111,10 @@ export class PayApiService { const channel = req.params?.channel || req.query?.channel || req.body?.channel; const outTradeNoFromReq = req.query?.outTradeNo || req.body?.out_trade_no || req.body?.outTradeNo; const payUnsafe = outTradeNoFromReq ? await this.corePayService.findByOutTradeNoUnsafe(outTradeNoFromReq) : null; - const siteId = payUnsafe?.siteId || req.user?.siteId || 0; + const siteId = payUnsafe?.site_id || req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const { adapter, config } = await this.paymentRegistry.resolve(siteId, type, channel); const result = await adapter.notify(config, { headers: req.headers, @@ -122,7 +125,7 @@ export class PayApiService { await this.corePayService.updateStatus(siteId, result.outTradeNo, 1, result.tradeNo); const pay = await this.corePayService.findByOutTradeNo(siteId, result.outTradeNo); if (pay) { - await this.domainEventService.publishPaymentEvent('succeeded', String(pay.id), String(siteId), { outTradeNo: pay.outTradeNo, tradeNo: pay.tradeNo }); + await this.domainEventService.publishPaymentEvent('succeeded', String(pay.id), String(siteId), { outTradeNo: pay.out_trade_no, tradeNo: pay.trade_no }); } } else if (result.status === 'CLOSED') { await this.corePayService.updateStatus(siteId, result.outTradeNo, 2); @@ -134,11 +137,11 @@ export class PayApiService { const pay = await this.corePayService.findByOutTradeNo(siteId, outTradeNo); if (!pay) return null; return { - outTradeNo: pay.outTradeNo, + outTradeNo: pay.out_trade_no, status: pay.status, - tradeNo: pay.tradeNo, - payTime: pay.payTime, - closeTime: pay.closeTime, + tradeNo: pay.trade_no, + payTime: pay.pay_time, + closeTime: pay.close_time, }; } @@ -159,7 +162,7 @@ export class PayApiService { refundMoney: body.refundMoney, reason: body.reason, }); - await this.domainEventService.publishPaymentEvent('refunded', String(pay.id), String(siteId), { outTradeNo: pay.outTradeNo, refundNo: body.refundNo, refundMoney: body.refundMoney }); + await this.domainEventService.publishPaymentEvent('refunded', String(pay.id), String(siteId), { outTradeNo: pay.out_trade_no, refundNo: body.refundNo, refundMoney: body.refundMoney }); return result; } } diff --git a/wwjcloud/src/common/pay/services/core/CorePayService.ts b/wwjcloud/src/common/pay/services/core/CorePayService.ts index 113fc86..71aad38 100644 --- a/wwjcloud/src/common/pay/services/core/CorePayService.ts +++ b/wwjcloud/src/common/pay/services/core/CorePayService.ts @@ -1,7 +1,6 @@ import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { Repository, Like } from "typeorm"; -import { BaseService } from "../../../../core/base/BaseService"; import { Pay } from "../../entities/Pay"; /** @@ -9,13 +8,11 @@ import { Pay } from "../../entities/Pay"; * 对应PHP: app\service\core\pay\CorePayService */ @Injectable() -export class CorePayService extends BaseService { +export class CorePayService { constructor( @InjectRepository(Pay) private readonly payRepository: Repository, - ) { - super(payRepository); - } + ) {} /** * 分页查询支付记录 @@ -29,24 +26,24 @@ export class CorePayService extends BaseService { .where("pay.site_id = :siteId", { siteId }) .select([ "pay.id", - "pay.outTradeNo", - "pay.tradeType", - "pay.tradeId", - "pay.tradeNo", + "pay.out_trade_no", + "pay.trade_type", + "pay.trade_id", + "pay.trade_no", "pay.body", "pay.money", "pay.voucher", "pay.status", "pay.type", "pay.channel", - "pay.failReason", - "pay.payTime", - "pay.closeTime", - "pay.createTime", + "pay.fail_reason", + "pay.pay_time", + "pay.close_time", + "pay.create_time", ]); if (where.outTradeNo) { - queryBuilder.andWhere("pay.outTradeNo LIKE :outTradeNo", { + queryBuilder.andWhere("pay.out_trade_no LIKE :outTradeNo", { outTradeNo: `%${where.outTradeNo}%`, }); } @@ -94,7 +91,7 @@ export class CorePayService extends BaseService { .andWhere("pay.type = :type", { type: "offline" }) .select([ "pay.id", - "pay.outTradeNo", + "pay.out_trade_no", "pay.type", "pay.money", "pay.body", @@ -106,7 +103,7 @@ export class CorePayService extends BaseService { ]); if (where.outTradeNo) { - queryBuilder.andWhere("pay.outTradeNo LIKE :outTradeNo", { + queryBuilder.andWhere("pay.out_trade_no LIKE :outTradeNo", { outTradeNo: `%${where.outTradeNo}%`, }); } @@ -141,23 +138,23 @@ export class CorePayService extends BaseService { */ async getDetail(siteId: number, id: number) { return await this.payRepository.findOne({ - where: { siteId, id }, + where: { site_id: siteId, id }, select: [ "id", - "outTradeNo", - "tradeType", - "tradeId", - "tradeNo", + "out_trade_no", + "trade_type", + "trade_id", + "trade_no", "body", "money", "voucher", "status", "type", "channel", - "failReason", - "payTime", - "closeTime", - "createTime", + "fail_reason", + "pay_time", + "close_time", + "create_time", ], }); } @@ -199,11 +196,11 @@ export class CorePayService extends BaseService { updateData.tradeNo = tradeNo; } } else if (status === 2) { - updateData.closeTime = new Date(); + updateData.close_time = new Date(); } const result = await this.payRepository.update( - { siteId, outTradeNo }, + { site_id: siteId, out_trade_no: outTradeNo }, updateData, ); return (result.affected || 0) > 0; @@ -228,11 +225,11 @@ export class CorePayService extends BaseService { */ async refuse(siteId: number, outTradeNo: string, reason: string): Promise { const result = await this.payRepository.update( - { siteId, outTradeNo }, + { site_id: siteId, out_trade_no: outTradeNo }, { status: 2, - failReason: reason, - closeTime: new Date(), + fail_reason: reason, + close_time: Math.floor(Date.now() / 1000), }, ); return (result.affected || 0) > 0; @@ -272,7 +269,7 @@ export class CorePayService extends BaseService { */ async findByOutTradeNo(siteId: number, outTradeNo: string) { return await this.payRepository.findOne({ - where: { siteId, outTradeNo }, + where: { site_id: siteId, out_trade_no: outTradeNo }, }); } @@ -281,7 +278,7 @@ export class CorePayService extends BaseService { */ async findByOutTradeNoUnsafe(outTradeNo: string) { return await this.payRepository.findOne({ - where: { outTradeNo }, + where: { out_trade_no: outTradeNo }, }); } @@ -292,7 +289,7 @@ export class CorePayService extends BaseService { const result = await this.payRepository .createQueryBuilder() .update(Pay) - .set({ status: 2, closeTime: () => 'CURRENT_TIMESTAMP' }) + .set({ status: 2, close_time: () => 'CURRENT_TIMESTAMP' }) .where('status = :status', { status: 0 }) .andWhere('create_time < :before', { before }) .execute(); @@ -381,7 +378,7 @@ export class CorePayService extends BaseService { .where('pay.site_id = :siteId', { siteId }); if (keyword) { - query.andWhere('pay.outTradeNo LIKE :keyword', { keyword: `%${keyword}%` }); + query.andWhere('pay.out_trade_no LIKE :keyword', { keyword: `%${keyword}%` }); } if (status !== '') { @@ -493,10 +490,10 @@ export class CorePayService extends BaseService { */ async manualComplete(siteId: number, outTradeNo: string) { const result = await this.payRepository.update( - { site_id: siteId, outTradeNo }, + { site_id: siteId, out_trade_no: outTradeNo }, { status: 1, - payTime: new Date(), + pay_time: Math.floor(Date.now() / 1000), update_time: Math.floor(Date.now() / 1000), } ); @@ -512,10 +509,10 @@ export class CorePayService extends BaseService { */ async cancel(siteId: number, outTradeNo: string) { const result = await this.payRepository.update( - { site_id: siteId, outTradeNo }, + { site_id: siteId, out_trade_no: outTradeNo }, { status: 2, - closeTime: new Date(), + close_time: Math.floor(Date.now() / 1000), update_time: Math.floor(Date.now() / 1000), } ); diff --git a/wwjcloud/src/common/rbac/entities/SysRole.ts b/wwjcloud/src/common/rbac/entities/SysRole.ts index c4baf7c..b0db11c 100644 --- a/wwjcloud/src/common/rbac/entities/SysRole.ts +++ b/wwjcloud/src/common/rbac/entities/SysRole.ts @@ -1,11 +1,13 @@ -import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm'; @Entity('sys_role') -export class SysRole extends BaseEntity { +export class SysRole { @PrimaryGeneratedColumn({ name: 'role_id' }) role_id: number; + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; + @Column({ name: 'role_name', type: 'varchar', @@ -19,7 +21,7 @@ export class SysRole extends BaseEntity { name: 'rules', type: 'text', nullable: true, - comment: '角色权限(菜单键数组JSON)', + comment: '角色权限(menus_id)', }) rules: string; @@ -27,10 +29,16 @@ export class SysRole extends BaseEntity { name: 'status', type: 'tinyint', default: 1, - comment: '状态:0=禁用,1=启用', + comment: '状态', }) status: number; + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '添加时间' }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '最后修改时间' }) + update_time: number; + // 业务逻辑方法 - �?PHP 项目保持一�? getStatusText(): string { const statusMap: { [key: number]: string } = { 0: '禁用', 1: '正常' }; diff --git a/wwjcloud/src/common/rbac/services/core/CoreRoleService.ts b/wwjcloud/src/common/rbac/services/core/CoreRoleService.ts index 8bd6517..04766ba 100644 --- a/wwjcloud/src/common/rbac/services/core/CoreRoleService.ts +++ b/wwjcloud/src/common/rbac/services/core/CoreRoleService.ts @@ -1,31 +1,29 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { BaseService } from '@wwjCore/base/BaseService'; import { SysRole } from '../../entities/SysRole'; @Injectable() -export class CoreRoleService extends BaseService { +export class CoreRoleService { constructor( @InjectRepository(SysRole) private sysRoleRepository: Repository, - ) { - super(sysRoleRepository); - } + ) {} async createRole(roleData: Partial): Promise { - return await this.create(roleData); + const role = this.sysRoleRepository.create(roleData); + return await this.sysRoleRepository.save(role); } async getRoleById(role_id: number): Promise { - return await this.findOne(role_id); + return await this.sysRoleRepository.findOne({ where: { role_id } }); } async getRoleByName( role_name: string, site_id: number, ): Promise { - return await this.findOneBy({ role_name, site_id }); + return await this.sysRoleRepository.findOne({ where: { role_name, site_id } }); } async updateRole( @@ -37,7 +35,7 @@ export class CoreRoleService extends BaseService { throw new NotFoundException('角色不存在'); } - await this.update(role_id, updateData); + await this.sysRoleRepository.update({ role_id }, updateData); const updatedRole = await this.getRoleById(role_id); if (!updatedRole) { throw new NotFoundException('角色更新后不存在'); @@ -51,15 +49,15 @@ export class CoreRoleService extends BaseService { throw new NotFoundException('角色不存在'); } - await this.delete(role_id); + await this.sysRoleRepository.delete({ role_id }); } async getRolesByAppType(site_id: number): Promise { - return await this.findMany({ site_id }); + return await this.sysRoleRepository.find({ where: { site_id } }); } async getActiveRolesByAppType(site_id: number): Promise { - return await this.findMany({ site_id, status: 1 }); + return await this.sysRoleRepository.find({ where: { site_id, status: 1 } }); } async isRoleNameExists( @@ -78,9 +76,9 @@ export class CoreRoleService extends BaseService { } async getRoleStats(site_id: number): Promise { - const total = await this.count({ site_id }); - const active = await this.count({ site_id, status: 1 }); - const inactive = await this.count({ site_id, status: 0 }); + const total = await this.sysRoleRepository.count({ where: { site_id } }); + const active = await this.sysRoleRepository.count({ where: { site_id, status: 1 } }); + const inactive = await this.sysRoleRepository.count({ where: { site_id, status: 0 } }); return { total, diff --git a/wwjcloud/src/common/site/controllers/admin/SiteAccountLogController.ts b/wwjcloud/src/common/site/controllers/admin/SiteAccountLogController.ts index 49d0a5c..3a1517c 100644 --- a/wwjcloud/src/common/site/controllers/admin/SiteAccountLogController.ts +++ b/wwjcloud/src/common/site/controllers/admin/SiteAccountLogController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Body, Query, UseGuards, Req } from '@nestjs/common'; +import { Controller, Get, Post, Body, Query, UseGuards, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation } from '@nestjs/swagger'; import type { Request } from 'express'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; @@ -21,17 +21,21 @@ export class SiteAccountLogController { @Get('page') @ApiOperation({ summary: '账单分页' }) async page(@Query() query: SiteAccountLogQueryDto, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const data = await this.service.getPage(siteId, query); - return { code: 200, message: '获取成功', data }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.service.getPage(siteId, query); } @Post() @ApiOperation({ summary: '新增账单' }) async add(@Body() body: CreateSiteAccountLogDto, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const data = await this.service.add(siteId, body); - return { code: 200, message: '创建成功', data }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.service.add(siteId, body); } } diff --git a/wwjcloud/src/common/site/controllers/admin/SiteController.ts b/wwjcloud/src/common/site/controllers/admin/SiteController.ts index 49d51c6..d2d6ccb 100644 --- a/wwjcloud/src/common/site/controllers/admin/SiteController.ts +++ b/wwjcloud/src/common/site/controllers/admin/SiteController.ts @@ -17,16 +17,14 @@ export class SiteController { @Get('page') @ApiOperation({ summary: '站点分页' }) async page(@Query() query: SiteQueryDto) { - const data = await this.service.getPage(query); - return { code: 200, message: '获取成功', data }; + return await this.service.getPage(query); } @Get(':siteId') @ApiOperation({ summary: '站点详情' }) @ApiParam({ name: 'siteId', description: '站点ID' }) async info(@Param('siteId', ParseIntPipe) siteId: number) { - const data = await this.service.getInfo(siteId); - return { code: 200, message: '获取成功', data }; + return await this.service.getInfo(siteId); } @Post() @@ -41,8 +39,7 @@ export class SiteController { if (siteId && payload.siteId && payload.siteId !== siteId) { throw new Error('越权操作:site_id 不匹配'); } - const data = await this.service.add(payload, req); - return { code: 200, message: '创建成功', data }; + return await this.service.add(payload, req); } @Put(':siteId') @@ -58,8 +55,7 @@ export class SiteController { if (requestSiteId && siteId !== requestSiteId) { throw new Error('越权操作:site_id 不匹配'); } - const data = await this.service.edit(siteId, payload, req); - return { code: 200, message: '更新成功', data }; + return await this.service.edit(siteId, payload, req); } @Delete(':siteId') @@ -71,8 +67,7 @@ export class SiteController { if (requestSiteId && siteId !== requestSiteId) { throw new Error('越权操作:site_id 不匹配'); } - const data = await this.service.del(siteId, req); - return { code: 200, message: '删除成功', data }; + return await this.service.del(siteId, req); } @Put(':siteId/status/:status') @@ -85,7 +80,6 @@ export class SiteController { if (requestSiteId && siteId !== requestSiteId) { throw new Error('越权操作:site_id 不匹配'); } - const data = await this.service.updateStatus(siteId, status, req); - return { code: 200, message: '更新成功', data }; + return await this.service.updateStatus(siteId, status, req); } } diff --git a/wwjcloud/src/common/site/controllers/admin/SiteGroupController.ts b/wwjcloud/src/common/site/controllers/admin/SiteGroupController.ts index 33f0241..d91721f 100644 --- a/wwjcloud/src/common/site/controllers/admin/SiteGroupController.ts +++ b/wwjcloud/src/common/site/controllers/admin/SiteGroupController.ts @@ -17,38 +17,33 @@ export class SiteGroupController { @Get('page') @ApiOperation({ summary: '分组分页' }) async page(@Query() query: SiteGroupQueryDto) { - const data = await this.service.getPage(query); - return { code: 200, message: '获取成功', data }; + return await this.service.getPage(query); } @Get(':group_id') @ApiOperation({ summary: '分组详情' }) @ApiParam({ name: 'group_id', description: '分组ID' }) async info(@Param('group_id', ParseIntPipe) group_id: number) { - const data = await this.service.getInfo(group_id); - return { code: 200, message: '获取成功', data }; + return await this.service.getInfo(group_id); } @Post() @ApiOperation({ summary: '新增分组' }) async add(@Body() body: CreateSiteGroupDto) { - const data = await this.service.add(body); - return { code: 200, message: '创建成功', data }; + return await this.service.add(body); } @Put(':group_id') @ApiOperation({ summary: '编辑分组' }) @ApiParam({ name: 'group_id', description: '分组ID' }) async edit(@Param('group_id', ParseIntPipe) group_id: number, @Body() body: UpdateSiteGroupDto) { - const data = await this.service.edit(group_id, body); - return { code: 200, message: '更新成功', data }; + return await this.service.edit(group_id, body); } @Delete(':group_id') @ApiOperation({ summary: '删除分组' }) @ApiParam({ name: 'group_id', description: '分组ID' }) async del(@Param('group_id', ParseIntPipe) group_id: number) { - const data = await this.service.del(group_id); - return { code: 200, message: '删除成功', data }; + return await this.service.del(group_id); } } diff --git a/wwjcloud/src/common/site/controllers/admin/SiteUserController.ts b/wwjcloud/src/common/site/controllers/admin/SiteUserController.ts index d332dd0..0da7654 100644 --- a/wwjcloud/src/common/site/controllers/admin/SiteUserController.ts +++ b/wwjcloud/src/common/site/controllers/admin/SiteUserController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Put, Post, Body, Param, Query, UseGuards, ParseIntPipe, Req } from '@nestjs/common'; +import { Controller, Get, Put, Post, Body, Param, Query, UseGuards, ParseIntPipe, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; @@ -20,18 +20,22 @@ export class SiteUserController { @Get('page') @ApiOperation({ summary: '用户分页' }) async page(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const data = await this.service.getPage(siteId, query); - return { code: 200, message: '获取成功', data }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.service.getPage(siteId, query); } @Get(':uid') @ApiOperation({ summary: '用户详情' }) @ApiParam({ name: 'uid', description: '用户ID' }) async info(@Param('uid', ParseIntPipe) uid: number, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const data = await this.service.getInfo(siteId, uid); - return { code: 200, message: '获取成功', data }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.service.getInfo(siteId, uid); } @Put(':uid/status/:status') @@ -40,8 +44,7 @@ export class SiteUserController { @Param('uid', ParseIntPipe) uid: number, @Param('status', ParseIntPipe) status: number, ) { - const data = await this.service.updateStatus(uid, status); - return { code: 200, message: '更新成功', data }; + return await this.service.updateStatus(uid, status); } @Post(':uid/roles') @@ -51,9 +54,11 @@ export class SiteUserController { @Body() body: { role_ids: string }, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const data = await this.service.assignRoles(siteId, uid, body.role_ids || ''); - return { code: 200, message: '更新成功', data }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.service.assignRoles(siteId, uid, body.role_ids || ''); } } diff --git a/wwjcloud/src/common/site/controllers/admin/UserLogController.ts b/wwjcloud/src/common/site/controllers/admin/UserLogController.ts index 684b1e8..924a10d 100644 --- a/wwjcloud/src/common/site/controllers/admin/UserLogController.ts +++ b/wwjcloud/src/common/site/controllers/admin/UserLogController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Query, UseGuards, Req } from '@nestjs/common'; +import { Controller, Get, Query, UseGuards, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation } from '@nestjs/swagger'; import type { Request } from 'express'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; @@ -20,9 +20,11 @@ export class UserLogController { @Get('page') @ApiOperation({ summary: '日志分页' }) async page(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const data = await this.service.getPage(siteId, query); - return { code: 200, message: '获取成功', data }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.service.getPage(siteId, query); } } diff --git a/wwjcloud/src/common/site/entities/Site.ts b/wwjcloud/src/common/site/entities/Site.ts index 1d6a74f..c8c4d8f 100644 --- a/wwjcloud/src/common/site/entities/Site.ts +++ b/wwjcloud/src/common/site/entities/Site.ts @@ -1,102 +1,104 @@ import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from "typeorm"; -import { BaseEntity } from "../../../core/base/BaseEntity"; /** * 站点实体 * 对应PHP: app\model\site\Site */ @Entity("site") -export class Site extends BaseEntity { +export class Site { @PrimaryGeneratedColumn({ name: "site_id" }) - siteId: number; + site_id: number; - @Column({ name: "site_name", length: 100, comment: "站点名称" }) - siteName: string; + @Column({ name: "site_name", type: "varchar", length: 50, default: "", comment: "站点名称" }) + site_name: string; - @Column({ name: "front_end_name", length: 100, default: "", comment: "前端名称" }) - frontEndName: string; + @Column({ name: "group_id", type: "int", default: 0, comment: "分组ID(0:不限制)" }) + group_id: number; - @Column({ name: "front_end_logo", length: 500, default: "", comment: "前端Logo" }) - frontEndLogo: string; - - @Column({ name: "front_end_icon", length: 500, default: "", comment: "前端图标" }) - frontEndIcon: string; - - @Column({ name: "app_type", length: 20, default: "site", comment: "应用类型" }) - appType: string; - - @Column({ name: "keywords", length: 200, default: "", comment: "关键词" }) + @Column({ name: "keywords", type: "varchar", length: 255, default: "", comment: "关键字" }) keywords: string; - @Column({ name: "logo", length: 500, default: "", comment: "Logo" }) + @Column({ name: "app_type", type: "varchar", length: 50, default: "admin", comment: "站点类型" }) + app_type: string; + + @Column({ name: "logo", type: "varchar", length: 255, default: "", comment: "站点logo" }) logo: string; - @Column({ name: "icon", length: 500, default: "", comment: "图标" }) - icon: string; - - @Column({ name: "desc", type: "text", default: "", comment: "描述" }) + @Column({ name: "desc", type: "varchar", length: 255, default: "", comment: "简介" }) desc: string; - @Column({ name: "status", type: "tinyint", default: 1, comment: "状态 0禁用 1启用" }) + @Column({ name: "status", type: "tinyint", default: 1, comment: "状态 1-正常 0-体验期 2-已到期" }) status: number; - @Column({ name: "latitude", type: "decimal", precision: 10, scale: 6, default: 0, comment: "纬度" }) - latitude: number; + @Column({ name: "latitude", type: "varchar", length: 255, default: "", comment: "纬度" }) + latitude: string; - @Column({ name: "longitude", type: "decimal", precision: 10, scale: 6, default: 0, comment: "经度" }) - longitude: number; + @Column({ name: "longitude", type: "varchar", length: 255, default: "", comment: "经度" }) + longitude: string; - @Column({ name: "province_id", type: "int", default: 0, comment: "省份ID" }) - provinceId: number; + @Column({ name: "province_id", type: "int", default: 0, comment: "省" }) + province_id: number; - @Column({ name: "city_id", type: "int", default: 0, comment: "城市ID" }) - cityId: number; + @Column({ name: "city_id", type: "int", default: 0, comment: "市" }) + city_id: number; - @Column({ name: "district_id", type: "int", default: 0, comment: "区县ID" }) - districtId: number; + @Column({ name: "district_id", type: "int", default: 0, comment: "区" }) + district_id: number; - @Column({ name: "address", length: 200, default: "", comment: "地址" }) + @Column({ name: "address", type: "varchar", length: 255, default: "", comment: "详细地址" }) address: string; - @Column({ name: "full_address", length: 500, default: "", comment: "完整地址" }) - fullAddress: string; + @Column({ name: "full_address", type: "varchar", length: 255, default: "", comment: "完整地址" }) + full_address: string; - @Column({ name: "phone", length: 20, default: "", comment: "电话" }) + @Column({ name: "phone", type: "varchar", length: 255, default: "", comment: "客服电话" }) phone: string; - @Column({ name: "business_hours", length: 200, default: "", comment: "营业时间" }) - businessHours: string; + @Column({ name: "business_hours", type: "varchar", length: 255, default: "", comment: "营业时间" }) + business_hours: string; - @Column({ name: "expire_time", type: "timestamp", nullable: true, comment: "过期时间" }) - expireTime: Date; + @CreateDateColumn({ name: "create_time", type: "int", default: 0, comment: "创建时间" }) + create_time: number; - @Column({ name: "group_id", type: "int", default: 0, comment: "分组ID" }) - groupId: number; + @Column({ name: "expire_time", type: "bigint", default: 0, comment: "到期时间(如果是0 无限期)" }) + expire_time: number; - @Column({ name: "app", type: "json", nullable: true, comment: "应用配置" }) - app: string[]; + @Column({ name: "front_end_name", type: "varchar", length: 50, default: "", comment: "前台名称" }) + front_end_name: string; - @Column({ name: "addons", type: "json", nullable: true, comment: "插件配置" }) - addons: string[]; + @Column({ name: "front_end_logo", type: "varchar", length: 255, default: "", comment: "前台logo" }) + front_end_logo: string; - @Column({ name: "initalled_addon", type: "json", nullable: true, comment: "已安装插件" }) - initalledAddon: string[]; + @Column({ name: "front_end_icon", type: "varchar", length: 255, default: "", comment: "前台图标" }) + front_end_icon: string; - @Column({ name: "site_domain", length: 200, default: "", comment: "站点域名" }) - siteDomain: string; + @Column({ name: "icon", type: "varchar", length: 255, default: "", comment: "图标" }) + icon: string; - @Column({ name: "meta_title", length: 200, default: "", comment: "SEO标题" }) - metaTitle: string; + @Column({ name: "member_no", type: "varchar", length: 50, default: "0", comment: "会员编号" }) + member_no: string; - @Column({ name: "meta_desc", length: 500, default: "", comment: "SEO描述" }) - metaDesc: string; + @Column({ name: "app", type: "text", default: "", comment: "应用" }) + app: string; - @Column({ name: "meta_keyword", length: 200, default: "", comment: "SEO关键词" }) - metaKeyword: string; + @Column({ name: "addons", type: "text", default: "", comment: "插件" }) + addons: string; - @CreateDateColumn({ name: "create_time", comment: "创建时间" }) - createTime: Date; + @Column({ name: "initalled_addon", type: "text", default: "", comment: "已安装插件" }) + initalled_addon: string; - @UpdateDateColumn({ name: "update_time", comment: "更新时间" }) - updateTime: Date; + @Column({ name: "site_domain", type: "varchar", length: 255, default: "", comment: "站点域名" }) + site_domain: string; + + @Column({ name: "meta_title", type: "varchar", length: 255, default: "", comment: "Meta 标题" }) + meta_title: string; + + @Column({ name: "meta_desc", type: "varchar", length: 255, default: "", comment: "Meta 描述" }) + meta_desc: string; + + @UpdateDateColumn({ name: "update_time", type: "int", default: 0, comment: "更新时间" }) + update_time: number; + + @Column({ name: "is_del", type: "tinyint", default: 0, comment: "是否删除" }) + is_del: number; } diff --git a/wwjcloud/src/common/site/entities/SiteAccountLog.ts b/wwjcloud/src/common/site/entities/SiteAccountLog.ts index f8860a4..b7a3c2b 100644 --- a/wwjcloud/src/common/site/entities/SiteAccountLog.ts +++ b/wwjcloud/src/common/site/entities/SiteAccountLog.ts @@ -1,4 +1,4 @@ -import { Entity, Column } from 'typeorm'; +import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; import { BaseEntity } from '../../../core/base/BaseEntity'; /** @@ -7,6 +7,8 @@ import { BaseEntity } from '../../../core/base/BaseEntity'; */ @Entity('site_account_log') export class SiteAccountLog extends BaseEntity { + @PrimaryGeneratedColumn({ name: 'id' }) + id: number; @Column({ name: 'type', type: 'varchar', length: 50, comment: '类型:pay支付,refund退款,transfer转账' }) type: string; diff --git a/wwjcloud/src/common/site/services/admin/SiteGroupService.ts b/wwjcloud/src/common/site/services/admin/SiteGroupService.ts index 8cbd28e..2a82a39 100644 --- a/wwjcloud/src/common/site/services/admin/SiteGroupService.ts +++ b/wwjcloud/src/common/site/services/admin/SiteGroupService.ts @@ -1,5 +1,5 @@ import { Injectable } from "@nestjs/common"; -import { CoreSiteGroupService } from "../core/CoreSiteGroupService"; +import { SiteGroupCoreService } from "../core/SiteGroupCoreService"; import { SiteGroup } from "../../entities/SiteGroup"; /** @@ -9,7 +9,7 @@ import { SiteGroup } from "../../entities/SiteGroup"; @Injectable() export class SiteGroupService { constructor( - private readonly coreSiteGroupService: CoreSiteGroupService, + private readonly coreSiteGroupService: SiteGroupCoreService, ) {} /** diff --git a/wwjcloud/src/common/site/services/admin/SiteService.ts b/wwjcloud/src/common/site/services/admin/SiteService.ts index a73694d..fa38ae5 100644 --- a/wwjcloud/src/common/site/services/admin/SiteService.ts +++ b/wwjcloud/src/common/site/services/admin/SiteService.ts @@ -110,28 +110,28 @@ export class SiteService { this.normalizeExpire(payload); // 校验 site_id 权限 - if (payload.siteId) { - this.validateSiteId(payload.siteId, req); + if (payload.site_id) { + this.validateSiteId(payload.site_id, req); } const site = await this.coreSiteService.add(payload); // 分组应用/插件同步到站点,并触发微页面加载 try { - if (payload.groupId) { - const group = await this.siteGroupCoreService.getInfo(Number(payload.groupId)); + if (payload.group_id) { + const group = await this.siteGroupCoreService.getInfo(Number(payload.group_id)); if (group) { await this.domainEventService.publishEvent( 'AddSiteAfter', - String(site.siteId ?? ''), - String(req?.user?.siteId ?? site.siteId ?? ''), - { site_id: site.siteId, main_app: group.app || [], site_addons: group.addon || [] }, + String(site.site_id ?? ''), + String(req?.user?.siteId ?? site.site_id ?? ''), + { site_id: site.site_id, main_app: group.app || [], site_addons: group.addon || [] }, ); // 加载微页面数据(对齐 PHP: DiyService->loadDiyData) await this.domainEventService.publishEvent( 'site.diy.load', - String(site.siteId ?? ''), - String(req?.user?.siteId ?? site.siteId ?? ''), - { site_id: site.siteId, main_app: group.app || [], tag: 'add' }, + String(site.site_id ?? ''), + String(req?.user?.siteId ?? site.site_id ?? ''), + { site_id: site.site_id, main_app: group.app || [], tag: 'add' }, ); } } @@ -141,14 +141,14 @@ export class SiteService { try { await this.domainEventService.publishEvent( 'site.site.added', - String(site.siteId ?? site['site_id'] ?? ''), - String((req?.user?.siteId ?? 0) || 0), - { siteId: site.siteId ?? site['site_id'], payload }, + String(site.site_id ?? ''), + String(req?.user?.siteId || site.site_id), + { siteId: site.site_id, payload }, ); } catch {} // 记录审计日志 - await this.logAudit('site.create', site.siteId || 0, data, req); - return site.siteId; + await this.logAudit('site.create', site.site_id, data, req); + return site.site_id; } async edit( @@ -167,12 +167,12 @@ export class SiteService { await this.domainEventService.publishEvent( 'site.site.updated', String(siteId), - String((req?.user?.siteId ?? 0) || 0), + String(req?.user?.siteId || siteId), { siteId, payload }, ); // 若分组变更,同步应用/插件并刷新微页面 - if (payload.groupId) { - const group = await this.siteGroupCoreService.getInfo(Number(payload.groupId)); + if (payload.group_id) { + const group = await this.siteGroupCoreService.getInfo(Number(payload.group_id)); if (group) { await this.domainEventService.publishEvent( 'AddSiteAfter', @@ -210,7 +210,7 @@ export class SiteService { await this.domainEventService.publishEvent( 'site.site.deleted', String(siteId), - String((req?.user?.siteId ?? 0) || 0), + String(req?.user?.siteId || siteId), { siteId }, ); } @@ -232,7 +232,7 @@ export class SiteService { await this.domainEventService.publishEvent( 'site.site.status_updated', String(siteId), - String((req?.user?.siteId ?? 0) || 0), + String(req?.user?.siteId || siteId), { siteId, status }, ); } @@ -267,7 +267,7 @@ export class SiteService { } // 触发初始化事件(对齐 PHP: event('SiteInit', ...)) try { - const group = site.groupId ? await this.siteGroupCoreService.getInfo(Number(site.groupId)) : null; + const group = site.group_id ? await this.siteGroupCoreService.getInfo(Number(site.group_id)) : null; await this.domainEventService.publishEvent( 'SiteInit', String(siteId), diff --git a/wwjcloud/src/common/site/services/core/CoreSiteService.ts b/wwjcloud/src/common/site/services/core/CoreSiteService.ts index 5ab39d5..ead76f0 100644 --- a/wwjcloud/src/common/site/services/core/CoreSiteService.ts +++ b/wwjcloud/src/common/site/services/core/CoreSiteService.ts @@ -1,7 +1,6 @@ import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { Repository, Like } from "typeorm"; -import { BaseService } from "../../../../core/base/BaseService"; import { Site } from "../../entities/Site"; /** @@ -9,13 +8,11 @@ import { Site } from "../../entities/Site"; * 对应PHP: app\service\core\site\CoreSiteService */ @Injectable() -export class CoreSiteService extends BaseService { +export class CoreSiteService { constructor( @InjectRepository(Site) private readonly siteRepository: Repository, - ) { - super(siteRepository); - } + ) {} /** * 分页查询站点列表 @@ -27,12 +24,12 @@ export class CoreSiteService extends BaseService { .createQueryBuilder("site") .where("site.app_type != :appType", { appType: "admin" }) .select([ - "site.siteId", - "site.siteName", - "site.frontEndName", - "site.frontEndLogo", - "site.frontEndIcon", - "site.appType", + "site.site_id", + "site.site_name", + "site.front_end_name", + "site.front_end_logo", + "site.front_end_icon", + "site.app_type", "site.keywords", "site.logo", "site.icon", @@ -40,23 +37,23 @@ export class CoreSiteService extends BaseService { "site.status", "site.latitude", "site.longitude", - "site.provinceId", - "site.cityId", - "site.districtId", + "site.province_id", + "site.city_id", + "site.district_id", "site.address", - "site.fullAddress", + "site.full_address", "site.phone", - "site.businessHours", - "site.createTime", - "site.expireTime", - "site.groupId", + "site.business_hours", + "site.create_time", + "site.expire_time", + "site.group_id", "site.app", "site.addons", - "site.siteDomain", + "site.site_domain", ]); if (where.siteName) { - queryBuilder.andWhere("site.siteName LIKE :siteName", { + queryBuilder.andWhere("site.site_name LIKE :siteName", { siteName: `%${where.siteName}%`, }); } @@ -110,14 +107,14 @@ export class CoreSiteService extends BaseService { */ async getInfo(siteId: number) { return await this.siteRepository.findOne({ - where: { siteId }, + where: { site_id: siteId }, select: [ - "siteId", - "siteName", - "frontEndName", - "frontEndLogo", - "frontEndIcon", - "appType", + "site_id", + "site_name", + "front_end_name", + "front_end_logo", + "front_end_icon", + "app_type", "keywords", "logo", "icon", @@ -125,22 +122,21 @@ export class CoreSiteService extends BaseService { "status", "latitude", "longitude", - "provinceId", - "cityId", - "districtId", + "province_id", + "city_id", + "district_id", "address", - "fullAddress", + "full_address", "phone", - "businessHours", - "createTime", - "expireTime", - "groupId", + "business_hours", + "create_time", + "expire_time", + "group_id", "app", "addons", - "siteDomain", - "metaTitle", - "metaDesc", - "metaKeyword", + "site_domain", + "meta_title", + "meta_desc", ], }); } @@ -153,7 +149,7 @@ export class CoreSiteService extends BaseService { async add(data: Partial): Promise { const siteData = { ...data, - appType: data.appType || "site", + appType: data.app_type || "site", createTime: new Date(), }; @@ -170,10 +166,10 @@ export class CoreSiteService extends BaseService { async edit(siteId: number, data: Partial): Promise { const updateData = { ...data, - updateTime: new Date(), + update_time: Math.floor(Date.now() / 1000), }; - const result = await this.siteRepository.update(siteId, updateData); + const result = await this.siteRepository.update({ site_id: siteId }, updateData); return (result.affected || 0) > 0; } @@ -220,10 +216,10 @@ export class CoreSiteService extends BaseService { */ async getExpireTime(siteId: number) { const site = await this.siteRepository.findOne({ - where: { siteId }, - select: ["expireTime"], + where: { site_id: siteId }, + select: ["expire_time"], }); - return site ? { expireTime: site.expireTime } : null; + return site ? { expireTime: site.expire_time } : null; } /** @@ -233,7 +229,7 @@ export class CoreSiteService extends BaseService { */ async findByDomain(domain: string) { return await this.siteRepository.findOne({ - where: { siteDomain: domain }, + where: { site_domain: domain }, }); } @@ -244,9 +240,9 @@ export class CoreSiteService extends BaseService { * @returns 是否成功 */ async updateStatus(siteId: number, status: number): Promise { - const result = await this.siteRepository.update(siteId, { + const result = await this.siteRepository.update({ site_id: siteId }, { status, - updateTime: new Date(), + update_time: Math.floor(Date.now() / 1000), }); return (result.affected || 0) > 0; } @@ -260,7 +256,7 @@ export class CoreSiteService extends BaseService { const result = await this.siteRepository .createQueryBuilder() .update(Site) - .set({ status: 0, updateTime: new Date() }) + .set({ status: 0, update_time: Math.floor(Date.now() / 1000) }) .where('status = :enabled', { enabled: 1 }) .andWhere('expire_time IS NOT NULL') .andWhere('expire_time < :before', { before }) diff --git a/wwjcloud/src/common/site/services/core/SiteGroupCoreService.ts b/wwjcloud/src/common/site/services/core/SiteGroupCoreService.ts index 87030fd..5c41303 100644 --- a/wwjcloud/src/common/site/services/core/SiteGroupCoreService.ts +++ b/wwjcloud/src/common/site/services/core/SiteGroupCoreService.ts @@ -28,6 +28,10 @@ export class SiteGroupCoreService { return this.repo.findOne({ where: { group_id } }); } + async getAll() { + return this.repo.find(); + } + async add(payload: Partial) { const entity = this.repo.create({ ...payload, create_time: Math.floor(Date.now() / 1000) }); return this.repo.save(entity); @@ -47,4 +51,9 @@ export class SiteGroupCoreService { const list = await this.repo.find(); return list.map((g) => ({ id: (g as any).group_id, label: g.group_name, children: [] })); } + + async checkAddon(_addons: string[]) { + // 预留校验逻辑;与 PHP 行为对齐可在此实现 + return true as any; + } } diff --git a/wwjcloud/src/common/site/site.module.ts b/wwjcloud/src/common/site/site.module.ts index 349bab7..bd6d3be 100644 --- a/wwjcloud/src/common/site/site.module.ts +++ b/wwjcloud/src/common/site/site.module.ts @@ -1,4 +1,5 @@ import { Module } from "@nestjs/common"; +import { CacheModule } from "@nestjs/cache-manager"; import { TypeOrmModule } from "@nestjs/typeorm"; import { Site } from "./entities/Site"; import { SiteGroup } from "./entities/SiteGroup"; @@ -6,6 +7,8 @@ import { SiteAccountLog } from "./entities/SiteAccountLog"; import { SiteAccount } from "./entities/SiteAccount"; import { SysUserLog } from "./entities/SysUserLog"; import { DiyModule } from "../diy/diy.module"; +import { SysUser } from "../admin/entities/SysUser"; +import { SysUserRole } from "../admin/entities/SysUserRole"; // Core Services import { CoreSiteService } from "./services/core/CoreSiteService"; @@ -33,8 +36,9 @@ import { DiyLoadEventHandler } from "./subscribers/diyLoadEventHandler"; */ @Module({ imports: [ - TypeOrmModule.forFeature([Site, SiteGroup, SiteAccountLog, SysUserLog, SiteAccount]), + TypeOrmModule.forFeature([Site, SiteGroup, SiteAccountLog, SysUserLog, SiteAccount, SysUser, SysUserRole]), DiyModule, + CacheModule.register(), ], providers: [ // Core Services diff --git a/wwjcloud/src/common/site/subscribers/diyLoadEventHandler.ts b/wwjcloud/src/common/site/subscribers/diyLoadEventHandler.ts index b9e3b25..aceb79d 100644 --- a/wwjcloud/src/common/site/subscribers/diyLoadEventHandler.ts +++ b/wwjcloud/src/common/site/subscribers/diyLoadEventHandler.ts @@ -17,7 +17,7 @@ export class DiyLoadEventHandler { @EventHandler('site.diy.load', { consumerGroup: 'site-diy-initializer' }) async onLoad(event: DomainEvent): Promise { const data = (event?.data || {}) as { site_id?: number; main_app?: string[]; tag?: 'add' | 'update' }; - const siteId = Number(data.site_id || 0); + const siteId = Number(data.site_id); if (!siteId) return; try { diff --git a/wwjcloud/src/common/sys/controllers/admin/AgreementController.ts b/wwjcloud/src/common/sys/controllers/admin/AgreementController.ts index 7a779f51eb071ca5358c6a43d2bc8a4ea1bef985..50ef6d8b342323a4c517eeed1adc52874282339c 100644 GIT binary patch delta 644 zcmaE$@I`*Y8eJU*1%^^z`45KXkb zKpWHyx5;*OtB-9~dW}VYeH4KFH=<$x#bT H93Tt;!vTdi delta 646 zcmew&|3G2Fn#n1QN*n*!uyZRg)BvFZg8_r}b8PtX#0JVunP9bf}yX!}jKD!2(J1gOtE3 zQh;(LKn&7{YDev6f6mK{L^!0BmX4V0&ndb&iRTF;e+kfil|WZkGjIV(g~=b;-35_C z2`(y%C9JF`*YW2~HsBYlCoQb@b?4O+6;=$^5c@$cW2gnXTT zA|3`!pa9GZ`uyS;4l= LpyO*9c!4AUvC4qN diff --git a/wwjcloud/src/common/sys/controllers/admin/AppController.ts b/wwjcloud/src/common/sys/controllers/admin/AppController.ts index 2ca8f78..fd35a37 100644 --- a/wwjcloud/src/common/sys/controllers/admin/AppController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/AppController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Param, Query, UseGuards, Req } from '@nestjs/common'; +import { Controller, Get, Param, Query, UseGuards, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation, @@ -42,9 +42,11 @@ export class AppController { @Query('type') type?: string, @Req() req?: AuthenticatedRequest, ) { - const siteId = req?.user?.siteId || 0; - const result = await this.appService.getAppList(); - return { code: 200, message: '获取成功', data: result }; + const siteId = req?.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.appService.getAppList(); } @Get(':appKey') @@ -55,9 +57,11 @@ export class AppController { @Param('appKey') appKey: string, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.appService.getAppInfo(appKey); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.appService.getAppInfo(appKey); } @Get('check/:appKey') diff --git a/wwjcloud/src/common/sys/controllers/admin/AreaController.ts b/wwjcloud/src/common/sys/controllers/admin/AreaController.ts index 6009b2a..5314d87 100644 --- a/wwjcloud/src/common/sys/controllers/admin/AreaController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/AreaController.ts @@ -20,10 +20,10 @@ import { AreaService } from '../../services/admin/AreaService'; /** * 地区管理控制器 - 管理端 - * 路由前缀: /adminapi/sys/area + * 路由前缀: /admin/sys/area */ @ApiTags('地区管理') -@Controller('adminapi/sys/area') +@Controller('admin/sys/area') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') export class AreaController { @@ -34,8 +34,7 @@ export class AreaController { @ApiQuery({ name: 'pid', description: '父级ID', required: false }) @ApiResponse({ status: 200, description: '获取成功' }) async getListByPid(@Query('pid', ParseIntPipe) pid: number = 0) { - const result = await this.areaService.getListByPid(pid); - return { code: 200, message: '获取成功', data: result }; + return await this.areaService.getListByPid(pid); } @Get('tree') @@ -43,8 +42,7 @@ export class AreaController { @ApiQuery({ name: 'level', description: '最大层级', required: false }) @ApiResponse({ status: 200, description: '获取成功' }) async getAreaTree(@Query('level', ParseIntPipe) level: number = 3) { - const result = await this.areaService.getAreaTree(level); - return { code: 200, message: '获取成功', data: result }; + return await this.areaService.getAreaTree(level); } @Get('search') @@ -56,8 +54,7 @@ export class AreaController { @Query('keyword') keyword: string, @Query('level', ParseIntPipe) level?: number, ) { - const result = await this.areaService.searchArea(keyword, level); - return { code: 200, message: '获取成功', data: result }; + return await this.areaService.searchArea(keyword, level); } @Get(':id') @@ -65,8 +62,7 @@ export class AreaController { @ApiParam({ name: 'id', description: '地区ID' }) @ApiResponse({ status: 200, description: '获取成功' }) async getAreaByAreaCode(@Param('id', ParseIntPipe) id: number) { - const result = await this.areaService.getAreaByAreaCode(id); - return { code: 200, message: '获取成功', data: result }; + return await this.areaService.getAreaByAreaCode(id); } @Get(':id/path') @@ -75,7 +71,7 @@ export class AreaController { @ApiResponse({ status: 200, description: '获取成功' }) async getFullPath(@Param('id', ParseIntPipe) id: number) { const result = await this.areaService.getFullPath(id); - return { code: 200, message: '获取成功', data: { path: result } }; + return { path: result }; } @Get('batch/:ids') @@ -87,7 +83,6 @@ export class AreaController { .split(',') .map((id) => parseInt(id.trim())) .filter((id) => !isNaN(id)); - const result = await this.areaService.getAreaByAreaCodes(idArray); - return { code: 200, message: '获取成功', data: result }; + return await this.areaService.getAreaByAreaCodes(idArray); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/AttachmentCategoryController.ts b/wwjcloud/src/common/sys/controllers/admin/AttachmentCategoryController.ts index 558cdb0..90c12d5 100644 --- a/wwjcloud/src/common/sys/controllers/admin/AttachmentCategoryController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/AttachmentCategoryController.ts @@ -10,6 +10,7 @@ UseGuards, Req, ParseIntPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -48,9 +49,11 @@ export class AttachmentCategoryController { @Query() query: AttachmentCategoryQueryDto, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentCategoryService.getPage(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.attachmentCategoryService.getPage(siteId, query); } @Get(':id') @@ -61,9 +64,11 @@ export class AttachmentCategoryController { @Param('id', ParseIntPipe) id: number, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentCategoryService.getInfo(siteId, id); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.attachmentCategoryService.getInfo(siteId, id); } @Post() @@ -73,13 +78,11 @@ export class AttachmentCategoryController { @Body() data: CreateAttachmentCategoryDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentCategoryService.add(siteId, data); - return { code: 200, message: '创建成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '创建失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.attachmentCategoryService.add(siteId, data); } @Put(':id') @@ -91,17 +94,15 @@ export class AttachmentCategoryController { @Body() data: UpdateAttachmentCategoryDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentCategoryService.edit( - siteId, - id, - data, - ); - return { code: 200, message: '更新成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '更新失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.attachmentCategoryService.edit( + siteId, + id, + data, + ); } @Delete(':id') @@ -112,12 +113,10 @@ export class AttachmentCategoryController { @Param('id', ParseIntPipe) id: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentCategoryService.del(siteId, id); - return { code: 200, message: '删除成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '删除失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.attachmentCategoryService.del(siteId, id); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/AttachmentController.ts b/wwjcloud/src/common/sys/controllers/admin/AttachmentController.ts index 60a7c81..03bc5a8 100644 --- a/wwjcloud/src/common/sys/controllers/admin/AttachmentController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/AttachmentController.ts @@ -10,6 +10,7 @@ UseGuards, Req, ParseIntPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -52,9 +53,11 @@ export class AttachmentController { @Query() query: AttachmentQueryDto, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentService.getPage(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.attachmentService.getPage(siteId, query); } @Get(':attId') @@ -65,9 +68,11 @@ export class AttachmentController { @Param('attId', ParseIntPipe) attId: number, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentService.getInfo(siteId, attId); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.attachmentService.getInfo(siteId, attId); } @Post() @@ -77,13 +82,11 @@ export class AttachmentController { @Body() data: CreateAttachmentDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentService.add(siteId, data); - return { code: 200, message: '创建成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '创建失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.attachmentService.add(siteId, data); } @Put(':attId') @@ -95,13 +98,11 @@ export class AttachmentController { @Body() data: UpdateAttachmentDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentService.edit(siteId, attId, data); - return { code: 200, message: '更新成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '更新失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.attachmentService.edit(siteId, attId, data); } @Put(':attId/category') @@ -113,17 +114,15 @@ export class AttachmentController { @Body() data: ModifyAttachmentCategoryDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentService.modifyCategory( - siteId, - attId, - data.cate_id, - ); - return { code: 200, message: '修改成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '修改失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.attachmentService.modifyCategory( + siteId, + attId, + data.cate_id, + ); } @Delete(':attId') @@ -134,13 +133,11 @@ export class AttachmentController { @Param('attId', ParseIntPipe) attId: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentService.del(siteId, attId); - return { code: 200, message: '删除成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '删除失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.attachmentService.del(siteId, attId); } @Delete('batch') @@ -150,15 +147,13 @@ export class AttachmentController { @Body() data: BatchDeleteAttachmentDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.attachmentService.batchDelete( - siteId, - data.att_ids, - ); - return { code: 200, message: '删除成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '删除失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.attachmentService.batchDelete( + siteId, + data.att_ids, + ); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/ChannelController.ts b/wwjcloud/src/common/sys/controllers/admin/ChannelController.ts index 92831d2..b3bec83 100644 --- a/wwjcloud/src/common/sys/controllers/admin/ChannelController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/ChannelController.ts @@ -42,7 +42,7 @@ export class ChannelController { @ApiResponse({ status: 200, description: '获取成功' }) async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) { // TODO: 实现渠道分页列表 - return { code: 200, message: '获取成功', data: { list: [], total: 0 } }; + return { list: [], total: 0 }; } @Get('list') @@ -50,7 +50,7 @@ export class ChannelController { @ApiResponse({ status: 200, description: '获取成功' }) async getList(@Query() query: any, @Req() req: AuthenticatedRequest) { // TODO: 实现渠道列表 - return { code: 200, message: '获取成功', data: [] }; + return []; } @Get(':id') @@ -62,7 +62,7 @@ export class ChannelController { @Req() req: AuthenticatedRequest, ) { // TODO: 实现渠道详情 - return { code: 200, message: '获取成功', data: null }; + return null; } @Post() @@ -70,7 +70,7 @@ export class ChannelController { @ApiResponse({ status: 200, description: '创建成功' }) async add(@Body() data: any, @Req() req: AuthenticatedRequest) { // TODO: 实现渠道新增 - return { code: 200, message: '创建成功', data: null }; + return null; } @Put(':id') @@ -83,7 +83,7 @@ export class ChannelController { @Req() req: AuthenticatedRequest, ) { // TODO: 实现渠道编辑 - return { code: 200, message: '更新成功', data: null }; + return null; } @Delete(':id') @@ -95,6 +95,6 @@ export class ChannelController { @Req() req: AuthenticatedRequest, ) { // TODO: 实现渠道删除 - return { code: 200, message: '删除成功', data: null }; + return null; } } diff --git a/wwjcloud/src/common/sys/controllers/admin/CommonController.ts b/wwjcloud/src/common/sys/controllers/admin/CommonController.ts index cc68202..b51e2df 100644 --- a/wwjcloud/src/common/sys/controllers/admin/CommonController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/CommonController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, UseGuards, Req } from '@nestjs/common'; +import { Controller, Get, Post, UseGuards, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import type { Request } from 'express'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; @@ -29,31 +29,47 @@ export class CommonController { @ApiOperation({ summary: '获取字典数据' }) @ApiResponse({ status: 200, description: '获取成功' }) async getDict(@Req() req: AuthenticatedRequest) { + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } // TODO: 实现字典数据获取 - return { code: 200, message: '获取成功', data: {} }; + return {}; } @Get('config') @ApiOperation({ summary: '获取系统配置' }) @ApiResponse({ status: 200, description: '获取成功' }) async getConfig(@Req() req: AuthenticatedRequest) { + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } // TODO: 实现系统配置获取 - return { code: 200, message: '获取成功', data: {} }; + return {}; } @Post('upload') @ApiOperation({ summary: '文件上传' }) @ApiResponse({ status: 200, description: '上传成功' }) async upload(@Req() req: AuthenticatedRequest) { + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } // TODO: 实现文件上传 - return { code: 200, message: '上传成功', data: null }; + return null; } @Get('captcha') @ApiOperation({ summary: '获取验证码' }) @ApiResponse({ status: 200, description: '获取成功' }) async getCaptcha(@Req() req: AuthenticatedRequest) { + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } // TODO: 实现验证码获取 - return { code: 200, message: '获取成功', data: null }; + return null; } } diff --git a/wwjcloud/src/common/sys/controllers/admin/ConfigController.ts b/wwjcloud/src/common/sys/controllers/admin/ConfigController.ts index fa7d6e9..79612c0 100644 --- a/wwjcloud/src/common/sys/controllers/admin/ConfigController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/ConfigController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Body, UseGuards, Req } from '@nestjs/common'; +import { Controller, Get, Post, Body, UseGuards, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import type { Request } from 'express'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; @@ -23,10 +23,10 @@ interface AuthenticatedRequest extends Request { /** * 系统配置控制器 - 管理端 - * 路由前缀: /adminapi/sys/config + * 路由前缀: /admin/sys/config */ @ApiTags('系统配置管理') -@Controller('adminapi/sys/config') +@Controller('admin/sys/config') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') export class ConfigController { @@ -36,13 +36,11 @@ export class ConfigController { @ApiOperation({ summary: '获取版权信息' }) @ApiResponse({ status: 200, description: '获取成功' }) async getCopyright(@Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const data = await this.configService.getCopyright(siteId); - return { - code: 200, - message: '获取成功', - data, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.configService.getCopyright(siteId); } @Post('copyright') @@ -52,26 +50,22 @@ export class ConfigController { @Body() copyrightDto: CopyrightDto, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.configService.setCopyright(siteId, copyrightDto); - return { - code: 200, - message: '设置成功', - data: result, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.configService.setCopyright(siteId, copyrightDto); } @Get('website') @ApiOperation({ summary: '获取网站信息' }) @ApiResponse({ status: 200, description: '获取成功' }) async getWebSite(@Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const data = await this.configService.getWebSite(siteId); - return { - code: 200, - message: '获取成功', - data, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.configService.getWebSite(siteId); } @Post('website') @@ -81,26 +75,22 @@ export class ConfigController { @Body() websiteDto: WebSiteDto, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.configService.setWebSite(siteId, websiteDto); - return { - code: 200, - message: '设置成功', - data: result, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.configService.setWebSite(siteId, websiteDto); } @Get('scene-domain') @ApiOperation({ summary: '获取场景域名配置' }) @ApiResponse({ status: 200, description: '获取成功' }) async getSceneDomain(@Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const data = await this.configService.getSceneDomain(siteId); - return { - code: 200, - message: '获取成功', - data, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.configService.getSceneDomain(siteId); } @Post('scene-domain') @@ -110,29 +100,25 @@ export class ConfigController { @Body() sceneDomainDto: SceneDomainDto, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.configService.setSceneDomain( + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.configService.setSceneDomain( siteId, sceneDomainDto, ); - return { - code: 200, - message: '设置成功', - data: result, - }; } @Get('service') @ApiOperation({ summary: '获取服务配置' }) @ApiResponse({ status: 200, description: '获取成功' }) async getService(@Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const data = await this.configService.getService(siteId); - return { - code: 200, - message: '获取成功', - data, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.configService.getService(siteId); } @Post('service') @@ -142,12 +128,10 @@ export class ConfigController { @Body() serviceDto: ServiceDto, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.configService.setService(siteId, serviceDto); - return { - code: 200, - message: '设置成功', - data: result, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.configService.setService(siteId, serviceDto); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/ExportController.ts b/wwjcloud/src/common/sys/controllers/admin/ExportController.ts index ca053a7..00d46f1 100644 --- a/wwjcloud/src/common/sys/controllers/admin/ExportController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/ExportController.ts @@ -9,6 +9,7 @@ UseGuards, Req, ParseIntPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -41,17 +42,18 @@ export class ExportController { @ApiOperation({ summary: '获取导出记录分页列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.exportService.getPage(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.exportService.getPage(siteId, query); } @Get('data-types') @ApiOperation({ summary: '获取导出数据类型列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getExportDataType(@Req() req: AuthenticatedRequest) { - const result = await this.exportService.getExportDataType(); - return { code: 200, message: '获取成功', data: result }; + return await this.exportService.getExportDataType(); } @Post('check') @@ -61,17 +63,15 @@ export class ExportController { @Body() data: { export_key: string; conditions?: any }, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.exportService.checkExportData( - siteId, - data.export_key, - data.conditions, - ); - return { code: 200, message: '检查成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '检查失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.exportService.checkExportData( + siteId, + data.export_key, + data.conditions, + ); } @Post('export') @@ -81,17 +81,15 @@ export class ExportController { @Body() data: { export_key: string; conditions?: any }, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.exportService.exportData( - siteId, - data.export_key, - data.conditions, - ); - return { code: 200, message: '导出任务创建成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '导出失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.exportService.exportData( + siteId, + data.export_key, + data.conditions, + ); } @Delete(':id') @@ -102,12 +100,10 @@ export class ExportController { @Param('id', ParseIntPipe) id: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.exportService.deleteRecord(siteId, id); - return { code: 200, message: '删除成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '删除失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.exportService.deleteRecord(siteId, id); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/PosterController.ts b/wwjcloud/src/common/sys/controllers/admin/PosterController.ts index ad669aa..068e3d4 100644 --- a/wwjcloud/src/common/sys/controllers/admin/PosterController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/PosterController.ts @@ -10,6 +10,7 @@ UseGuards, Req, ParseIntPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -42,26 +43,29 @@ export class PosterController { @ApiOperation({ summary: '获取海报分页列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.posterService.getPage(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.posterService.getPage(siteId, query); } @Get('list') @ApiOperation({ summary: '获取海报列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getList(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.posterService.getList(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.posterService.getList(siteId, query); } @Get('types') @ApiOperation({ summary: '获取海报类型列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getPosterTypes(@Req() req: AuthenticatedRequest) { - const result = await this.posterService.getPosterTypes(); - return { code: 200, message: '获取成功', data: result }; + return await this.posterService.getPosterTypes(); } @Get('default/:type') @@ -72,9 +76,11 @@ export class PosterController { @Param('type') type: string, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.posterService.getDefaultByType(siteId, type); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.posterService.getDefaultByType(siteId, type); } @Get(':id') @@ -85,22 +91,22 @@ export class PosterController { @Param('id', ParseIntPipe) id: number, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.posterService.getInfo(siteId, id); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.posterService.getInfo(siteId, id); } @Post() @ApiOperation({ summary: '新增海报' }) @ApiResponse({ status: 200, description: '创建成功' }) async add(@Body() data: any, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.posterService.add(siteId, data); - return { code: 200, message: '创建成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '创建失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.posterService.add(siteId, data); } @Put(':id') @@ -112,13 +118,11 @@ export class PosterController { @Body() data: any, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.posterService.edit(siteId, id, data); - return { code: 200, message: '更新成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '更新失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.posterService.edit(siteId, id, data); } @Put(':id/default') @@ -130,13 +134,11 @@ export class PosterController { @Body() data: { type: string }, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.posterService.setDefault(siteId, id, data.type); - return { code: 200, message: '设置成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '设置失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.posterService.setDefault(siteId, id, data.type); } @Delete(':id') @@ -147,12 +149,10 @@ export class PosterController { @Param('id', ParseIntPipe) id: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.posterService.del(siteId, id); - return { code: 200, message: '删除成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '删除失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.posterService.del(siteId, id); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/PrinterController.ts b/wwjcloud/src/common/sys/controllers/admin/PrinterController.ts index 49e8aac..609e90c 100644 --- a/wwjcloud/src/common/sys/controllers/admin/PrinterController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/PrinterController.ts @@ -10,6 +10,7 @@ import { UseGuards, Req, ParseIntPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -42,26 +43,29 @@ export class PrinterController { @ApiOperation({ summary: '获取打印机分页列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.printerService.getPage(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.printerService.getPage(siteId, query); } @Get('list') @ApiOperation({ summary: '获取打印机列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getList(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.printerService.getList(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.printerService.getList(siteId, query); } @Get('brands') @ApiOperation({ summary: '获取打印机品牌列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getBrandList() { - const result = this.printerService.getBrandList(); - return { code: 200, message: '获取成功', data: result }; + return this.printerService.getBrandList(); } @Get(':printerId') @@ -72,22 +76,22 @@ export class PrinterController { @Param('printerId', ParseIntPipe) printerId: number, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.printerService.getInfo(siteId, printerId); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.printerService.getInfo(siteId, printerId); } @Post() @ApiOperation({ summary: '新增打印机' }) @ApiResponse({ status: 200, description: '创建成功' }) async add(@Body() data: any, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerService.add(siteId, data); - return { code: 200, message: '创建成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '创建失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerService.add(siteId, data); } @Put(':printerId') @@ -99,13 +103,11 @@ export class PrinterController { @Body() data: any, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerService.edit(siteId, printerId, data); - return { code: 200, message: '更新成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '更新失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerService.edit(siteId, printerId, data); } @Put(':printerId/status') @@ -117,17 +119,15 @@ export class PrinterController { @Body() data: { status: number }, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerService.modifyStatus( - siteId, - printerId, - data.status, - ); - return { code: 200, message: '修改成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '修改失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerService.modifyStatus( + siteId, + printerId, + data.status, + ); } @Post(':printerId/test') @@ -138,16 +138,14 @@ export class PrinterController { @Param('printerId', ParseIntPipe) printerId: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerService.testConnection( - siteId, - printerId, - ); - return { code: 200, message: '测试完成', data: result }; - } catch (error) { - return { code: 400, message: error.message || '测试失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerService.testConnection( + siteId, + printerId, + ); } @Post(':printerId/print') @@ -159,17 +157,15 @@ export class PrinterController { @Body() data: { content: string }, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerService.print( - siteId, - printerId, - data.content, - ); - return { code: 200, message: '打印完成', data: result }; - } catch (error) { - return { code: 400, message: error.message || '打印失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerService.print( + siteId, + printerId, + data.content, + ); } @Delete(':printerId') @@ -180,12 +176,10 @@ export class PrinterController { @Param('printerId', ParseIntPipe) printerId: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerService.del(siteId, printerId); - return { code: 200, message: '删除成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '删除失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerService.del(siteId, printerId); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/PrinterTemplateController.ts b/wwjcloud/src/common/sys/controllers/admin/PrinterTemplateController.ts index 2bedc62..27ddfa5 100644 --- a/wwjcloud/src/common/sys/controllers/admin/PrinterTemplateController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/PrinterTemplateController.ts @@ -10,6 +10,7 @@ UseGuards, Req, ParseIntPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -44,26 +45,29 @@ export class PrinterTemplateController { @ApiOperation({ summary: '获取打印模板分页列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.printerTemplateService.getPage(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.printerTemplateService.getPage(siteId, query); } @Get('list') @ApiOperation({ summary: '获取打印模板列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getList(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.printerTemplateService.getList(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.printerTemplateService.getList(siteId, query); } @Get('types') @ApiOperation({ summary: '获取模板类型列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getTemplateTypes(@Req() req: AuthenticatedRequest) { - const result = await this.printerTemplateService.getTemplateTypes(); - return { code: 200, message: '获取成功', data: result }; + return await this.printerTemplateService.getTemplateTypes(); } @Get('by-type/:type') @@ -74,12 +78,14 @@ export class PrinterTemplateController { @Param('type') type: string, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.printerTemplateService.getTemplatesByType( + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.printerTemplateService.getTemplatesByType( siteId, type, ); - return { code: 200, message: '获取成功', data: result }; } @Get(':templateId') @@ -90,25 +96,25 @@ export class PrinterTemplateController { @Param('templateId', ParseIntPipe) templateId: number, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.printerTemplateService.getInfo( + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.printerTemplateService.getInfo( siteId, templateId, ); - return { code: 200, message: '获取成功', data: result }; } @Post() @ApiOperation({ summary: '新增打印模板' }) @ApiResponse({ status: 200, description: '创建成功' }) async add(@Body() data: any, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerTemplateService.add(siteId, data); - return { code: 200, message: '创建成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '创建失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerTemplateService.add(siteId, data); } @Put(':templateId') @@ -120,17 +126,15 @@ export class PrinterTemplateController { @Body() data: any, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerTemplateService.edit( - siteId, - templateId, - data, - ); - return { code: 200, message: '更新成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '更新失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerTemplateService.edit( + siteId, + templateId, + data, + ); } @Post(':templateId/preview') @@ -142,17 +146,15 @@ export class PrinterTemplateController { @Body() data: { preview_data?: any }, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerTemplateService.previewTemplate( - siteId, - templateId, - data.preview_data, - ); - return { code: 200, message: '预览成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '预览失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerTemplateService.previewTemplate( + siteId, + templateId, + data.preview_data, + ); } @Delete(':templateId') @@ -163,12 +165,10 @@ export class PrinterTemplateController { @Param('templateId', ParseIntPipe) templateId: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.printerTemplateService.del(siteId, templateId); - return { code: 200, message: '删除成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '删除失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.printerTemplateService.del(siteId, templateId); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/RoleController.ts b/wwjcloud/src/common/sys/controllers/admin/RoleController.ts index b8d86f4..e8db8ac 100644 --- a/wwjcloud/src/common/sys/controllers/admin/RoleController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/RoleController.ts @@ -10,6 +10,7 @@ import { UseGuards, Req, ParseIntPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, @@ -45,7 +46,7 @@ interface AuthenticatedRequest extends Request { * 对应PHP: app\adminapi\controller\sys\Role */ @ApiTags('角色管理') -@Controller('adminapi/sys/role') +@Controller('admin/sys/role') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') export class RoleController { @@ -58,46 +59,32 @@ export class RoleController { @Query() query: RoleQueryDto, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.roleService.getPage(siteId, query); - return { - code: 200, - message: '获取成功', - data: result, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.roleService.getPage(siteId, query); } @Get('all') - @ApiOperation({ summary: '获取所有角色列表' }) + @ApiOperation({ summary: '获取所有角色' }) @ApiResponse({ status: 200, description: '获取成功' }) - async getAll(@Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const userId = req.user?.uid || 0; - - // TODO: 实现用户权限检查 - // 暂时假设为超级管理员,后续完善权限模块时补充 - const isAdmin = true; - const userRoleIds: number[] = []; - - const result = await this.roleService.getAll(siteId, userRoleIds, isAdmin); - return { - code: 200, - message: '获取成功', - data: result, - }; + async getAll(@Query('siteId') siteId?: number, @Query('isAdmin') isAdmin?: boolean) { + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.roleService.getAll(siteId, [], isAdmin); } @Get('column') @ApiOperation({ summary: '获取角色键值对' }) @ApiResponse({ status: 200, description: '获取成功' }) async getColumn(@Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.roleService.getColumn(siteId); - return { - code: 200, - message: '获取成功', - data: result, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.roleService.getColumn(siteId); } @Get(':roleId') @@ -105,12 +92,7 @@ export class RoleController { @ApiParam({ name: 'roleId', description: '角色ID' }) @ApiResponse({ status: 200, description: '获取成功' }) async getInfo(@Param('roleId', ParseIntPipe) roleId: number) { - const result = await this.roleService.getInfo(roleId); - return { - code: 200, - message: '获取成功', - data: result, - }; + return await this.roleService.getInfo(roleId); } @Post() @@ -120,31 +102,21 @@ export class RoleController { @Body() createRoleDto: CreateRoleDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const appType = 'admin'; // 默认为admin类型 - - // 处理rules字段 - const roleData = { - ...createRoleDto, - rules: createRoleDto.rules - ? JSON.stringify(createRoleDto.rules) - : undefined, - }; - - const result = await this.roleService.add(siteId, appType, roleData); - return { - code: 200, - message: '创建成功', - data: result, - }; - } catch (error) { - return { - code: 400, - message: error.message || '创建失败', - data: null, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + const appType = 'admin'; // 默认为admin类型 + + // 处理rules字段 + const roleData = { + ...createRoleDto, + rules: createRoleDto.rules + ? JSON.stringify(createRoleDto.rules) + : undefined, + }; + + return await this.roleService.add(siteId, appType, roleData); } @Put(':roleId') @@ -156,30 +128,20 @@ export class RoleController { @Body() updateRoleDto: UpdateRoleDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - - // 处理rules字段 - const roleData = { - ...updateRoleDto, - rules: updateRoleDto.rules - ? JSON.stringify(updateRoleDto.rules) - : undefined, - }; - - const result = await this.roleService.edit(roleId, siteId, roleData); - return { - code: 200, - message: '更新成功', - data: result, - }; - } catch (error) { - return { - code: 400, - message: error.message || '更新失败', - data: null, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + + // 处理rules字段 + const roleData = { + ...updateRoleDto, + rules: updateRoleDto.rules + ? JSON.stringify(updateRoleDto.rules) + : undefined, + }; + + return await this.roleService.edit(roleId, siteId, roleData); } @Put('status/:roleId') @@ -191,25 +153,15 @@ export class RoleController { @Body() modifyStatusDto: ModifyRoleStatusDto, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.roleService.modifyStatus( - roleId, - siteId, - modifyStatusDto.status, - ); - return { - code: 200, - message: '修改成功', - data: result, - }; - } catch (error) { - return { - code: 400, - message: error.message || '修改失败', - data: null, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.roleService.modifyStatus( + roleId, + siteId, + modifyStatusDto.status, + ); } @Delete(':roleId') @@ -220,21 +172,11 @@ export class RoleController { @Param('roleId', ParseIntPipe) roleId: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.roleService.del(roleId, siteId); - return { - code: 200, - message: '删除成功', - data: result, - }; - } catch (error) { - return { - code: 400, - message: error.message || '删除失败', - data: null, - }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.roleService.del(roleId, siteId); } @Get('menu-ids/:roleIds') @@ -251,7 +193,10 @@ export class RoleController { @Query('allow_menu_keys') allowMenuKeys: string = '', @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } const roleIdArray = roleIds .split(',') .map((id) => parseInt(id.trim())) @@ -263,15 +208,10 @@ export class RoleController { .filter((key) => key) : []; - const result = await this.roleService.getMenuIdsByRoleIds( + return await this.roleService.getMenuIdsByRoleIds( siteId, roleIdArray, allowMenuKeyArray, ); - return { - code: 200, - message: '获取成功', - data: result, - }; } } diff --git a/wwjcloud/src/common/sys/controllers/admin/ScheduleController.ts b/wwjcloud/src/common/sys/controllers/admin/ScheduleController.ts index d2bb286..b512643 100644 --- a/wwjcloud/src/common/sys/controllers/admin/ScheduleController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/ScheduleController.ts @@ -10,6 +10,7 @@ UseGuards, Req, ParseIntPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -42,18 +43,22 @@ export class ScheduleController { @ApiOperation({ summary: '获取定时任务分页列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.scheduleService.getPage(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.scheduleService.getPage(siteId, query); } @Get('list') @ApiOperation({ summary: '获取定时任务列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getList(@Query() query: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.scheduleService.getList(siteId, query); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.scheduleService.getList(siteId, query); } @Get(':id') @@ -64,22 +69,22 @@ export class ScheduleController { @Param('id', ParseIntPipe) id: number, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.scheduleService.getInfo(siteId, id); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.scheduleService.getInfo(siteId, id); } @Post() @ApiOperation({ summary: '新增定时任务' }) @ApiResponse({ status: 200, description: '创建成功' }) async add(@Body() data: any, @Req() req: AuthenticatedRequest) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.scheduleService.add(siteId, data); - return { code: 200, message: '创建成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '创建失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.scheduleService.add(siteId, data); } @Put(':id') @@ -91,13 +96,11 @@ export class ScheduleController { @Body() data: any, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.scheduleService.edit(siteId, id, data); - return { code: 200, message: '更新成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '更新失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.scheduleService.edit(siteId, id, data); } @Put(':id/start') @@ -108,13 +111,11 @@ export class ScheduleController { @Param('id', ParseIntPipe) id: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.scheduleService.start(siteId, id); - return { code: 200, message: '启动成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '启动失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.scheduleService.start(siteId, id); } @Put(':id/stop') @@ -125,13 +126,11 @@ export class ScheduleController { @Param('id', ParseIntPipe) id: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.scheduleService.stop(siteId, id); - return { code: 200, message: '停止成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '停止失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.scheduleService.stop(siteId, id); } @Delete(':id') @@ -142,12 +141,10 @@ export class ScheduleController { @Param('id', ParseIntPipe) id: number, @Req() req: AuthenticatedRequest, ) { - try { - const siteId = req.user?.siteId || 0; - const result = await this.scheduleService.del(siteId, id); - return { code: 200, message: '删除成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '删除失败', data: null }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); } + return await this.scheduleService.del(siteId, id); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/ScheduleLogController.ts b/wwjcloud/src/common/sys/controllers/admin/ScheduleLogController.ts index 30382ce..04e5db2 100644 --- a/wwjcloud/src/common/sys/controllers/admin/ScheduleLogController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/ScheduleLogController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Query, UseGuards, Req } from '@nestjs/common'; +import { Controller, Get, Query, UseGuards, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import type { Request } from 'express'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; @@ -29,27 +29,35 @@ export class ScheduleLogController { @ApiOperation({ summary: '获取定时任务日志分页列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) { + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } // TODO: 实现定时任务日志分页列表 - return { code: 200, message: '获取成功', data: { list: [], total: 0 } }; + return { list: [], total: 0 }; } @Get('list') @ApiOperation({ summary: '获取定时任务日志列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getList(@Query() query: any, @Req() req: AuthenticatedRequest) { + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } // TODO: 实现定时任务日志列表 - return { code: 200, message: '获取成功', data: [] }; + return []; } @Get('stats') @ApiOperation({ summary: '获取定时任务统计信息' }) @ApiResponse({ status: 200, description: '获取成功' }) async getStats(@Req() req: AuthenticatedRequest) { + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } // TODO: 实现定时任务统计信息 - return { - code: 200, - message: '获取成功', - data: { total: 0, success: 0, failed: 0 }, - }; + return { total: 0, success: 0, failed: 0 }; } } diff --git a/wwjcloud/src/common/sys/controllers/admin/SystemController.ts b/wwjcloud/src/common/sys/controllers/admin/SystemController.ts index 5713877..ca2ad84 100644 --- a/wwjcloud/src/common/sys/controllers/admin/SystemController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/SystemController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, UseGuards, Req } from '@nestjs/common'; +import { Controller, Get, Post, UseGuards, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import type { Request } from 'express'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; @@ -17,10 +17,10 @@ interface AuthenticatedRequest extends Request { /** * 系统信息管理控制器 - 管理端 - * 路由前缀: /adminapi/sys/system + * 路由前缀: /admin/sys/system */ @ApiTags('系统信息') -@Controller('adminapi/sys/system') +@Controller('admin/sys/system') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') export class SystemController { @@ -30,52 +30,45 @@ export class SystemController { @ApiOperation({ summary: '获取系统信息' }) @ApiResponse({ status: 200, description: '获取成功' }) async getInfo(@Req() req: AuthenticatedRequest) { - const result = await this.systemService.getInfo(); - return { code: 200, message: '获取成功', data: result }; + return await this.systemService.getInfo(); } @Get('url') @ApiOperation({ summary: '获取系统URL信息' }) @ApiResponse({ status: 200, description: '获取成功' }) async getUrl(@Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.systemService.getUrl(siteId); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.systemService.getUrl(siteId); } @Get('stats') @ApiOperation({ summary: '获取系统统计信息' }) @ApiResponse({ status: 200, description: '获取成功' }) async getSystemStats(@Req() req: AuthenticatedRequest) { - const result = await this.systemService.getSystemStats(); - return { code: 200, message: '获取成功', data: result }; + return await this.systemService.getSystemStats(); } @Get('system-info') @ApiOperation({ summary: '获取详细系统信息' }) @ApiResponse({ status: 200, description: '获取成功' }) async getSystemInfo(@Req() req: AuthenticatedRequest) { - const result = await this.systemService.getSystemInfo(); - return { code: 200, message: '获取成功', data: result }; + return await this.systemService.getSystemInfo(); } @Post('clear-cache') @ApiOperation({ summary: '清理系统缓存' }) @ApiResponse({ status: 200, description: '清理成功' }) async clearCache(@Req() req: AuthenticatedRequest) { - try { - const result = await this.systemService.clearCache(); - return { code: 200, message: '清理成功', data: result }; - } catch (error) { - return { code: 400, message: error.message || '清理失败', data: null }; - } + return await this.systemService.clearCache(); } @Get('check-config') @ApiOperation({ summary: '检查系统配置' }) @ApiResponse({ status: 200, description: '检查完成' }) async checkSystemConfig(@Req() req: AuthenticatedRequest) { - const result = await this.systemService.checkSystemConfig(); - return { code: 200, message: '检查完成', data: result }; + return await this.systemService.checkSystemConfig(); } } diff --git a/wwjcloud/src/common/sys/controllers/admin/UeditorController.ts b/wwjcloud/src/common/sys/controllers/admin/UeditorController.ts index 55216f9..8cf07ce 100644 --- a/wwjcloud/src/common/sys/controllers/admin/UeditorController.ts +++ b/wwjcloud/src/common/sys/controllers/admin/UeditorController.ts @@ -16,10 +16,10 @@ interface AuthenticatedRequest extends Request { /** * 富文本编辑器控制器 - 管理端 - * 路由前缀: /adminapi/sys/ueditor + * 路由前缀: /admin/sys/ueditor */ @ApiTags('富文本编辑器') -@Controller('adminapi/sys/ueditor') +@Controller('admin/sys/ueditor') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') export class UeditorController { @@ -49,7 +49,7 @@ export class UeditorController { @ApiResponse({ status: 200, description: '上传成功' }) async upload(@Req() req: AuthenticatedRequest) { // TODO: 实现编辑器文件上传 - return { code: 200, message: '上传成功', data: null }; + return null; } @Get('list') @@ -57,6 +57,6 @@ export class UeditorController { @ApiResponse({ status: 200, description: '获取成功' }) async getFileList(@Query() query: any, @Req() req: AuthenticatedRequest) { // TODO: 实现文件列表获取 - return { code: 200, message: '获取成功', data: { list: [], total: 0 } }; + return { list: [], total: 0 }; } } diff --git a/wwjcloud/src/common/sys/controllers/api/ApiAreaController.ts b/wwjcloud/src/common/sys/controllers/api/ApiAreaController.ts index 7f2940f..30bd2bc 100644 --- a/wwjcloud/src/common/sys/controllers/api/ApiAreaController.ts +++ b/wwjcloud/src/common/sys/controllers/api/ApiAreaController.ts @@ -6,6 +6,7 @@ Req, ParseIntPipe, Query, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -34,9 +35,11 @@ export class ApiAreaController { @Req() req: AuthenticatedRequest, @Query('parent_id') parentId?: number, ) { - const siteId = req.user?.siteId || 0; - const result = await this.apiAreaService.getAreaList(siteId, parentId); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiAreaService.getAreaList(siteId, parentId); } @Get(':areaId') @@ -47,8 +50,10 @@ export class ApiAreaController { @Param('areaId', ParseIntPipe) areaId: number, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.apiAreaService.getAreaInfo(siteId, areaId); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiAreaService.getAreaInfo(siteId, areaId); } } diff --git a/wwjcloud/src/common/sys/controllers/api/ApiConfigController.ts b/wwjcloud/src/common/sys/controllers/api/ApiConfigController.ts index 0af82a0..23deaae 100644 --- a/wwjcloud/src/common/sys/controllers/api/ApiConfigController.ts +++ b/wwjcloud/src/common/sys/controllers/api/ApiConfigController.ts @@ -6,6 +6,7 @@ Query, UseGuards, Req, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -22,7 +23,7 @@ interface AuthenticatedRequest extends Request { } @ApiTags('API配置') -@Controller('api/sys/config') +@Controller('api/sys/settings') @UseGuards(JwtAuthGuard) export class ApiConfigController { constructor(private readonly apiConfigService: ApiConfigService) {} @@ -31,9 +32,11 @@ export class ApiConfigController { @ApiOperation({ summary: '获取配置' }) @ApiResponse({ status: 200, description: '获取成功' }) async getConfig(@Query('key') key: string, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.apiConfigService.getConfig(siteId, key); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiConfigService.getConfig(siteId, key); } @Post('batch') @@ -43,8 +46,10 @@ export class ApiConfigController { @Body() body: { keys: string[] }, @Req() req: AuthenticatedRequest, ) { - const siteId = req.user?.siteId || 0; - const result = await this.apiConfigService.getConfigs(siteId, body.keys); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiConfigService.getConfigs(siteId, body.keys); } } diff --git a/wwjcloud/src/common/sys/controllers/api/ApiIndexController.ts b/wwjcloud/src/common/sys/controllers/api/ApiIndexController.ts index c7d90f9..6e46369 100644 --- a/wwjcloud/src/common/sys/controllers/api/ApiIndexController.ts +++ b/wwjcloud/src/common/sys/controllers/api/ApiIndexController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, UseGuards, Req } from '@nestjs/common'; +import { Controller, Get, UseGuards, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import type { Request } from 'express'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; @@ -14,7 +14,7 @@ interface AuthenticatedRequest extends Request { } @ApiTags('API首页') -@Controller('api/sys/index') +@Controller('api/sys/home') @UseGuards(JwtAuthGuard) export class ApiIndexController { constructor(private readonly apiIndexService: ApiIndexService) {} @@ -23,16 +23,17 @@ export class ApiIndexController { @ApiOperation({ summary: '获取首页信息' }) @ApiResponse({ status: 200, description: '获取成功' }) async getIndexInfo(@Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.apiIndexService.getIndexInfo(siteId); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiIndexService.getIndexInfo(siteId); } @Get('system') @ApiOperation({ summary: '获取系统信息' }) @ApiResponse({ status: 200, description: '获取成功' }) async getSystemInfo(@Req() req: AuthenticatedRequest) { - const result = await this.apiIndexService.getSystemInfo(); - return { code: 200, message: '获取成功', data: result }; + return await this.apiIndexService.getSystemInfo(); } } diff --git a/wwjcloud/src/common/sys/controllers/api/ApiScanController.ts b/wwjcloud/src/common/sys/controllers/api/ApiScanController.ts index 58accdf..3724fcd 100644 --- a/wwjcloud/src/common/sys/controllers/api/ApiScanController.ts +++ b/wwjcloud/src/common/sys/controllers/api/ApiScanController.ts @@ -1,4 +1,4 @@ -import { Controller, Post, Body, UseGuards, Req } from '@nestjs/common'; +import { Controller, Post, Body, UseGuards, Req, UnauthorizedException } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import type { Request } from 'express'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; @@ -26,8 +26,11 @@ export class ApiScanController { @Body() body: { code: string }, @Req() req: AuthenticatedRequest, ) { - const result = await this.apiScanService.scanQrCode(body.code); - return { code: 200, message: '扫描成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiScanService.scanQrCode(body.code); } @Post('barcode') @@ -37,7 +40,10 @@ export class ApiScanController { @Body() body: { code: string }, @Req() req: AuthenticatedRequest, ) { - const result = await this.apiScanService.scanBarcode(body.code); - return { code: 200, message: '扫描成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiScanService.scanBarcode(body.code); } } diff --git a/wwjcloud/src/common/sys/controllers/api/ApiTaskController.ts b/wwjcloud/src/common/sys/controllers/api/ApiTaskController.ts index f283215..928361a 100644 --- a/wwjcloud/src/common/sys/controllers/api/ApiTaskController.ts +++ b/wwjcloud/src/common/sys/controllers/api/ApiTaskController.ts @@ -8,6 +8,7 @@ UseGuards, Req, ParseIntPipe, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger'; import type { Request } from 'express'; @@ -33,18 +34,22 @@ export class ApiTaskController { @ApiOperation({ summary: '获取任务列表' }) @ApiResponse({ status: 200, description: '获取成功' }) async getTaskList(@Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.apiTaskService.getTaskList(siteId); - return { code: 200, message: '获取成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiTaskService.getTaskList(siteId); } @Post() @ApiOperation({ summary: '创建任务' }) @ApiResponse({ status: 200, description: '创建成功' }) async createTask(@Body() body: any, @Req() req: AuthenticatedRequest) { - const siteId = req.user?.siteId || 0; - const result = await this.apiTaskService.createTask(siteId, body); - return { code: 200, message: '创建成功', data: result }; + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiTaskService.createTask(siteId, body); } @Put(':taskId/status') @@ -56,10 +61,13 @@ export class ApiTaskController { @Body() body: { status: string }, @Req() req: AuthenticatedRequest, ) { - const result = await this.apiTaskService.updateTaskStatus( + const siteId = req.user?.siteId; + if (!siteId) { + throw new UnauthorizedException('未授权访问:缺少 site_id'); + } + return await this.apiTaskService.updateTaskStatus( taskId, body.status, ); - return { code: 200, message: '更新成功', data: result }; } } diff --git a/wwjcloud/src/common/sys/entities/SysAttachment.ts b/wwjcloud/src/common/sys/entities/SysAttachment.ts index 1fce157..1d8247a 100644 --- a/wwjcloud/src/common/sys/entities/SysAttachment.ts +++ b/wwjcloud/src/common/sys/entities/SysAttachment.ts @@ -1,8 +1,7 @@ -import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm'; @Entity('sys_attachment') -export class SysAttachment extends BaseEntity { +export class SysAttachment { @PrimaryGeneratedColumn({ name: 'att_id' }) att_id: number; @@ -81,6 +80,15 @@ export class SysAttachment extends BaseEntity { }) storage_type: string; + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '上传时间' }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '更新时间' }) + update_time: number; + // 获取文件扩展名 getFileExtension(): string { return this.real_name.split('.').pop() || ''; diff --git a/wwjcloud/src/common/sys/entities/SysConfig.ts b/wwjcloud/src/common/sys/entities/SysConfig.ts index 24f5781..748ecf7 100644 --- a/wwjcloud/src/common/sys/entities/SysConfig.ts +++ b/wwjcloud/src/common/sys/entities/SysConfig.ts @@ -1,44 +1,49 @@ -import { Entity, PrimaryGeneratedColumn, Column, Index } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; +import { Entity, PrimaryGeneratedColumn, Column, Index, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm'; /** * 系统配置实体 * 对应数据表: sys_config */ @Entity('sys_config') -@Index(['siteId', 'key'], { unique: true }) -export class SysConfig extends BaseEntity { +@Index(['site_id', 'config_key'], { unique: true }) +export class SysConfig { @PrimaryGeneratedColumn() id: number; - @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点ID' }) - siteId: number; + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; - @Column({ name: 'key', type: 'varchar', length: 100, comment: '配置键' }) - key: string; + @Column({ name: 'config_key', type: 'varchar', length: 255, default: '', comment: '配置项关键字' }) + config_key: string; @Column({ name: 'value', type: 'text', nullable: true, - comment: '配置值(JSON格式)', + comment: '配置值json', }) value: string; @Column({ - name: 'desc', - type: 'varchar', - length: 255, - nullable: true, - comment: '配置描述', - }) - desc?: string; - - @Column({ - name: 'is_use', + name: 'status', type: 'tinyint', default: 1, - comment: '是否启用:0=否,1=是', + comment: '是否启用 1启用 0不启用', }) - isUse: number; + status: number; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '创建时间' }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '修改时间' }) + update_time: number; + + @Column({ name: 'addon', type: 'varchar', length: 255, default: '', comment: '所属插件' }) + addon: string; + + @Column({ name: 'is_del', type: 'tinyint', default: 0, comment: '是否删除' }) + is_del: number; + + @DeleteDateColumn({ name: 'delete_time', type: 'int', default: 0, comment: '删除时间' }) + delete_time: number; } diff --git a/wwjcloud/src/common/sys/entities/SysMenu.ts b/wwjcloud/src/common/sys/entities/SysMenu.ts index 706cc22..ba34b34 100644 --- a/wwjcloud/src/common/sys/entities/SysMenu.ts +++ b/wwjcloud/src/common/sys/entities/SysMenu.ts @@ -6,26 +6,26 @@ UpdateDateColumn, DeleteDateColumn, } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; /** * 系统菜单实体 */ @Entity('sys_menu') -export class SysMenu extends BaseEntity { +export class SysMenu { @PrimaryGeneratedColumn() id: number; - @Column({ name: 'menu_name', length: 100, comment: '菜单名称' }) - menuName: string; + @Column({ name: 'menu_name', type: 'varchar', length: 100, default: '', comment: '菜单名称' }) + menu_name: string; @Column({ name: 'menu_short_name', + type: 'varchar', length: 50, nullable: true, comment: '菜单简称', }) - menuShortName: string; + menu_short_name: string; @Column({ name: 'menu_type', @@ -33,34 +33,37 @@ export class SysMenu extends BaseEntity { default: 1, comment: '菜单类型 1目录 2菜单 3按钮', }) - menuType: number; + menu_type: number; @Column({ name: 'parent_id', type: 'int', default: 0, comment: '父级菜单ID' }) - parentId: number; + parent_id: number; @Column({ name: 'menu_key', + type: 'varchar', length: 100, nullable: true, comment: '菜单标识', }) - menuKey: string; + menu_key: string; @Column({ name: 'menu_url', + type: 'varchar', length: 255, nullable: true, comment: '菜单链接', }) - menuUrl: string; + menu_url: string; @Column({ name: 'menu_icon', + type: 'varchar', length: 100, nullable: true, comment: '菜单图标', }) - menuIcon: string; + menu_icon: string; @Column({ name: 'sort', type: 'int', default: 0, comment: '排序' }) sort: number; @@ -79,7 +82,7 @@ export class SysMenu extends BaseEntity { default: 1, comment: '是否显示 0不显示 1显示', }) - isShow: number; + is_show: number; @Column({ name: 'is_del', @@ -87,16 +90,19 @@ export class SysMenu extends BaseEntity { default: 0, comment: '是否删除 0未删除 1已删除', }) - isDel: number; + is_del: number; - @CreateDateColumn({ name: 'create_time', comment: '创建时间' }) - createTime: Date; + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '创建时间' }) + create_time: number; - @UpdateDateColumn({ name: 'update_time', comment: '更新时间' }) - updateTime: Date; + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '更新时间' }) + update_time: number; - @DeleteDateColumn({ name: 'delete_time', comment: '删除时间' }) - deleteTime: Date; + @DeleteDateColumn({ name: 'delete_time', type: 'int', default: 0, comment: '删除时间' }) + delete_time: number; + + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; // 虚拟字段 statusName?: string; diff --git a/wwjcloud/src/common/sys/entities/SysNotice.ts b/wwjcloud/src/common/sys/entities/SysNotice.ts index daa821a..f846541 100644 --- a/wwjcloud/src/common/sys/entities/SysNotice.ts +++ b/wwjcloud/src/common/sys/entities/SysNotice.ts @@ -5,41 +5,48 @@ CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; /** * 系统通知实体 */ @Entity('sys_notice') -export class SysNotice extends BaseEntity { +export class SysNotice { @PrimaryGeneratedColumn() id: number; - @Column({ name: 'title', length: 200, comment: '通知标题' }) - title: string; + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点ID' }) + site_id: number; - @Column({ name: 'content', type: 'text', comment: '通知内容' }) - content: string; + @Column({ name: 'key', type: 'varchar', length: 50, default: '', comment: '标识' }) + key: string; - @Column({ - name: 'type', - type: 'tinyint', - default: 1, - comment: '通知类型 1系统通知 2用户通知', - }) - type: number; + @Column({ name: 'sms_content', type: 'text', nullable: true, comment: '短信配置参数' }) + sms_content: string; - @Column({ - name: 'status', - type: 'tinyint', - default: 1, - comment: '状态 0禁用 1启用', - }) - status: number; + @Column({ name: 'is_wechat', type: 'tinyint', default: 0, comment: '公众号模板消息(0:关闭,1:开启)' }) + is_wechat: number; - @CreateDateColumn({ name: 'create_time', comment: '创建时间' }) - createTime: Date; + @Column({ name: 'is_weapp', type: 'tinyint', default: 0, comment: '小程序订阅消息(0:关闭,1:开启)' }) + is_weapp: number; - @UpdateDateColumn({ name: 'update_time', comment: '更新时间' }) - updateTime: Date; + @Column({ name: 'is_sms', type: 'tinyint', default: 0, comment: '发送短信(0:关闭,1:开启)' }) + is_sms: number; + + @Column({ name: 'wechat_template_id', type: 'varchar', length: 255, default: '', comment: '微信模版消息id' }) + wechat_template_id: string; + + @Column({ name: 'weapp_template_id', type: 'varchar', length: 255, default: '', comment: '微信小程序订阅消息id' }) + weapp_template_id: string; + + @Column({ name: 'sms_id', type: 'varchar', length: 255, default: '', comment: '短信id(对应短信配置)' }) + sms_id: string; + + @Column({ name: 'wechat_first', type: 'varchar', length: 255, default: '', comment: '微信头部' }) + wechat_first: string; + + @Column({ name: 'wechat_remark', type: 'varchar', length: 255, default: '', comment: '微信说明' }) + wechat_remark: string; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '添加时间' }) + create_time: number; } diff --git a/wwjcloud/src/common/sys/entities/SysRole.ts b/wwjcloud/src/common/sys/entities/SysRole.ts index bb29d50..cc59116 100644 --- a/wwjcloud/src/common/sys/entities/SysRole.ts +++ b/wwjcloud/src/common/sys/entities/SysRole.ts @@ -4,45 +4,40 @@ Column, CreateDateColumn, UpdateDateColumn, + DeleteDateColumn, } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; /** * 系统角色实体 */ @Entity('sys_role') -export class SysRole extends BaseEntity { +export class SysRole { @PrimaryGeneratedColumn({ name: 'role_id' }) - roleId: number; + role_id: number; - @Column({ name: 'role_name', length: 50, comment: '角色名称' }) - roleName: string; + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; - @Column({ name: 'role_key', length: 50, comment: '角色标识' }) - roleKey: string; + @Column({ name: 'role_name', type: 'varchar', length: 255, default: '', comment: '角色名称' }) + role_name: string; - @Column({ name: 'sort', type: 'int', default: 0, comment: '排序' }) - sort: number; + @Column({ name: 'rules', type: 'text', nullable: true, comment: '角色权限(menus_id)' }) + rules: string; - @Column({ - name: 'status', - type: 'tinyint', - default: 1, - comment: '状态 0禁用 1启用', - }) + @Column({ name: 'status', type: 'tinyint', default: 1, comment: '状态' }) status: number; - @Column({ name: 'remark', length: 500, nullable: true, comment: '备注' }) - remark: string; + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '添加时间' }) + create_time: number; - @Column({ name: 'rules', type: 'json', nullable: true, comment: '权限规则' }) - rules: string[]; + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '最后修改时间' }) + update_time: number; - @CreateDateColumn({ name: 'create_time', comment: '创建时间' }) - createTime: Date; + @Column({ name: 'is_del', type: 'tinyint', default: 0, comment: '是否删除' }) + is_del: number; - @UpdateDateColumn({ name: 'update_time', comment: '更新时间' }) - updateTime: Date; + @DeleteDateColumn({ name: 'delete_time', type: 'int', default: 0, comment: '删除时间' }) + delete_time: number; // 虚拟字段 statusName?: string; diff --git a/wwjcloud/src/common/sys/entities/SysSchedule.ts b/wwjcloud/src/common/sys/entities/SysSchedule.ts index 40b0212..7ff1b0a 100644 --- a/wwjcloud/src/common/sys/entities/SysSchedule.ts +++ b/wwjcloud/src/common/sys/entities/SysSchedule.ts @@ -4,63 +4,52 @@ Column, CreateDateColumn, UpdateDateColumn, + DeleteDateColumn, } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; /** * 定时任务实体 */ @Entity('sys_schedule') -export class SysSchedule extends BaseEntity { +export class SysSchedule { @PrimaryGeneratedColumn() id: number; - @Column({ name: 'key', length: 100, comment: '任务标识' }) + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; + + @Column({ name: 'addon', type: 'varchar', length: 255, default: '', comment: '所属插件' }) + addon: string; + + @Column({ name: 'key', type: 'varchar', length: 255, default: '', comment: '计划任务模板key' }) key: string; - @Column({ name: 'title', length: 100, comment: '任务标题' }) - title: string; - - @Column({ name: 'command', length: 500, comment: '执行命令' }) - command: string; - - @Column({ - name: 'time', - type: 'json', - nullable: true, - comment: '执行时间配置', - }) - time: any; - - @Column({ - name: 'last_time', - type: 'timestamp', - nullable: true, - comment: '最后执行时间', - }) - lastTime: Date; - - @Column({ - name: 'next_time', - type: 'timestamp', - nullable: true, - comment: '下次执行时间', - }) - nextTime: Date; - - @Column({ - name: 'status', - type: 'tinyint', - default: 1, - comment: '状态 0禁用 1启用', - }) + @Column({ name: 'status', type: 'int', default: 1, comment: '任务状态 是否启用' }) status: number; - @CreateDateColumn({ name: 'create_time', comment: '创建时间' }) - createTime: Date; + @Column({ name: 'time', type: 'varchar', length: 500, default: '', comment: '任务周期 json结构' }) + time: string; - @UpdateDateColumn({ name: 'update_time', comment: '更新时间' }) - updateTime: Date; + @Column({ name: 'count', type: 'int', default: 0, comment: '执行次数' }) + count: number; + + @Column({ name: 'last_time', type: 'int', default: 0, comment: '最后执行时间' }) + last_time: number; + + @Column({ name: 'next_time', type: 'int', default: 0, comment: '下次执行时间' }) + next_time: number; + + @Column({ name: 'sort', type: 'int', default: 0, comment: '排序' }) + sort: number; + + @CreateDateColumn({ name: 'create_time', type: 'int', default: 0, comment: '创建时间' }) + create_time: number; + + @UpdateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '更新时间' }) + update_time: number; + + @DeleteDateColumn({ name: 'delete_time', type: 'int', default: 0, comment: '删除时间' }) + delete_time: number; // 虚拟字段 statusName?: string; diff --git a/wwjcloud/src/common/sys/services/admin/RoleService.ts b/wwjcloud/src/common/sys/services/admin/RoleService.ts index deee3dd..8031da9 100644 --- a/wwjcloud/src/common/sys/services/admin/RoleService.ts +++ b/wwjcloud/src/common/sys/services/admin/RoleService.ts @@ -24,7 +24,8 @@ export class RoleService { * 删除用户组 */ async delete(role_id: number) { - return this.coreRoleService.delete(role_id); + // Core 层方法名为 del,且需要 siteId;暂无 siteId 时传 0 与 PHP 语义对齐 + return this.coreRoleService.del(role_id as any, 0 as any); } /** diff --git a/wwjcloud/src/common/sys/services/core/CoreAttachmentService.ts b/wwjcloud/src/common/sys/services/core/CoreAttachmentService.ts index 8c33b9e..9fc083e 100644 --- a/wwjcloud/src/common/sys/services/core/CoreAttachmentService.ts +++ b/wwjcloud/src/common/sys/services/core/CoreAttachmentService.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, Like } from 'typeorm'; -import { BaseService } from '../../../../core/base/BaseService'; import { SysAttachment } from '../../entities/SysAttachment'; /** @@ -9,13 +8,11 @@ import { SysAttachment } from '../../entities/SysAttachment'; * 对应PHP: CoreAttachmentService */ @Injectable() -export class CoreAttachmentService extends BaseService { +export class CoreAttachmentService { constructor( @InjectRepository(SysAttachment) private readonly attachmentRepository: Repository, - ) { - super(attachmentRepository); - } + ) {} /** * 分页查询附件列表 @@ -42,8 +39,8 @@ export class CoreAttachmentService extends BaseService { 'attachment.real_name', 'attachment.path', 'attachment.url', - 'attachment.file_size', - 'attachment.file_type', + 'attachment.att_size', + 'attachment.att_type', 'attachment.cate_id', 'attachment.create_time', ]); diff --git a/wwjcloud/src/common/sys/services/core/CoreRoleService.ts b/wwjcloud/src/common/sys/services/core/CoreRoleService.ts index d07ce3f..76b1c69 100644 --- a/wwjcloud/src/common/sys/services/core/CoreRoleService.ts +++ b/wwjcloud/src/common/sys/services/core/CoreRoleService.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, In } from 'typeorm'; -import { BaseService } from '../../../../core/base/BaseService'; import { SysRole } from '../../../rbac/entities/SysRole'; /** @@ -9,13 +8,11 @@ import { SysRole } from '../../../rbac/entities/SysRole'; * 对应PHP: 角色核心操作逻辑 */ @Injectable() -export class CoreRoleService extends BaseService { +export class CoreRoleService { constructor( @InjectRepository(SysRole) private readonly roleRepository: Repository, - ) { - super(roleRepository); - } + ) {} /** * 分页查询角色列表 diff --git a/wwjcloud/src/common/sys/services/core/CoreSysConfigService.ts b/wwjcloud/src/common/sys/services/core/CoreSysConfigService.ts index 60cc558..0027f24 100644 --- a/wwjcloud/src/common/sys/services/core/CoreSysConfigService.ts +++ b/wwjcloud/src/common/sys/services/core/CoreSysConfigService.ts @@ -1,21 +1,18 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; -import { BaseService } from '../../../../core/base/BaseService'; +import { Repository, In } from 'typeorm'; import { SysConfig } from '../../entities/SysConfig'; @Injectable() -export class CoreSysConfigService extends BaseService { +export class CoreSysConfigService { constructor( @InjectRepository(SysConfig) private readonly configRepository: Repository, - ) { - super(configRepository); - } + ) {} async getConfigByKey(siteId: number, key: string): Promise { const config = await this.configRepository.findOne({ - where: { site_id: siteId, key }, + where: { site_id: siteId, config_key: key }, }); return config?.value || null; } @@ -26,19 +23,19 @@ export class CoreSysConfigService extends BaseService { value: string, ): Promise { const existingConfig = await this.configRepository.findOne({ - where: { site_id: siteId, key }, + where: { site_id: siteId, config_key: key }, }); if (existingConfig) { const result = await this.configRepository.update( - { site_id: siteId, key }, + { site_id: siteId, config_key: key }, { value, update_time: Math.floor(Date.now() / 1000) }, ); return (result.affected || 0) > 0; } else { const config = this.configRepository.create({ site_id: siteId, - key, + config_key: key, value, create_time: Math.floor(Date.now() / 1000), }); @@ -52,12 +49,12 @@ export class CoreSysConfigService extends BaseService { keys: string[], ): Promise> { const configs = await this.configRepository.find({ - where: { site_id: siteId, key: keys as any }, + where: { site_id: siteId, config_key: In(keys) }, }); const result: Record = {}; configs.forEach((config) => { - result[config.key] = config.value; + result[config.config_key] = config.value; }); return result; @@ -66,7 +63,7 @@ export class CoreSysConfigService extends BaseService { async deleteConfig(siteId: number, key: string): Promise { const result = await this.configRepository.delete({ site_id: siteId, - key, + config_key: key, }); return (result.affected || 0) > 0; } diff --git a/wwjcloud/src/common/sys/services/core/CoreSysService.ts b/wwjcloud/src/common/sys/services/core/CoreSysService.ts index 7bf15d0..08e5337 100644 --- a/wwjcloud/src/common/sys/services/core/CoreSysService.ts +++ b/wwjcloud/src/common/sys/services/core/CoreSysService.ts @@ -1,20 +1,17 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, In } from 'typeorm'; -import { BaseService } from '@wwjCore/base/BaseService'; import { SysConfig } from '../../entities/SysConfig'; import { SysArea } from '../../entities/SysArea'; @Injectable() -export class CoreSysService extends BaseService { +export class CoreSysService { constructor( @InjectRepository(SysConfig) private configRepository: Repository, @InjectRepository(SysArea) private areaRepository: Repository, - ) { - super(configRepository); - } + ) {} /** * 获取系统信息 diff --git a/wwjcloud/src/common/sys/services/core/CoreUeditorService.ts b/wwjcloud/src/common/sys/services/core/CoreUeditorService.ts index ed74f69..dfe3843 100644 --- a/wwjcloud/src/common/sys/services/core/CoreUeditorService.ts +++ b/wwjcloud/src/common/sys/services/core/CoreUeditorService.ts @@ -1,27 +1,23 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { BaseService } from '../../../../core/base/BaseService'; import { SysAttachment } from '../../entities/SysAttachment'; @Injectable() -export class CoreUeditorService extends BaseService { +export class CoreUeditorService { constructor( @InjectRepository(SysAttachment) private readonly attachmentRepository: Repository, - ) { - super(attachmentRepository); - } + ) {} async uploadImage(data: any) { const attachment = this.attachmentRepository.create({ site_id: data.site_id as any, - file_name: data.fileName, - file_path: data.filePath, - file_url: data.fileUrl, - file_size: data.fileSize, - file_type: 'image', - mime_type: data.mimeType, + name: data.fileName, + path: data.filePath, + url: data.fileUrl, + att_size: data.fileSize, + att_type: 'image', create_time: Math.floor(Date.now() / 1000), } as any); @@ -31,12 +27,11 @@ export class CoreUeditorService extends BaseService { async uploadFile(data: any) { const attachment = this.attachmentRepository.create({ site_id: data.site_id as any, - file_name: data.fileName, - file_path: data.filePath, - file_url: data.fileUrl, - file_size: data.fileSize, - file_type: 'file', - mime_type: data.mimeType, + name: data.fileName, + path: data.filePath, + url: data.fileUrl, + att_size: data.fileSize, + att_type: 'file', create_time: Math.floor(Date.now() / 1000), } as any); @@ -46,12 +41,11 @@ export class CoreUeditorService extends BaseService { async uploadVideo(data: any) { const attachment = this.attachmentRepository.create({ site_id: data.site_id as any, - file_name: data.fileName, - file_path: data.filePath, - file_url: data.fileUrl, - file_size: data.fileSize, - file_type: 'video', - mime_type: data.mimeType, + name: data.fileName, + path: data.filePath, + url: data.fileUrl, + att_size: data.fileSize, + att_type: 'video', create_time: Math.floor(Date.now() / 1000), } as any); @@ -62,7 +56,7 @@ export class CoreUeditorService extends BaseService { const { page = 1, limit = 20, site_id } = query; const qb = this.attachmentRepository.createQueryBuilder('attachment'); - qb.andWhere('attachment.file_type = :type', { type: 'image' }); + qb.andWhere('attachment.att_type = :type', { type: 'image' }); if (site_id) { qb.andWhere('attachment.site_id = :site_id', { site_id }); } @@ -79,7 +73,7 @@ export class CoreUeditorService extends BaseService { const qb = this.attachmentRepository.createQueryBuilder('attachment'); if (file_type) { - qb.andWhere('attachment.file_type = :type', { type: file_type }); + qb.andWhere('attachment.att_type = :type', { type: file_type }); } if (site_id) { qb.andWhere('attachment.site_id = :site_id', { site_id }); diff --git a/wwjcloud/src/common/sys/sys.module.ts b/wwjcloud/src/common/sys/sys.module.ts index 5321827..a036db2 100644 --- a/wwjcloud/src/common/sys/sys.module.ts +++ b/wwjcloud/src/common/sys/sys.module.ts @@ -91,6 +91,10 @@ import { ChannelService } from './services/admin/ChannelService'; import { CommonService } from './services/admin/CommonService'; import { CoreChannelService } from './services/core/CoreChannelService'; import { CoreCommonService } from './services/core/CoreCommonService'; +import { CoreUeditorService } from './services/core/CoreUeditorService'; +import { UeditorService } from './services/admin/UeditorService'; +import { CoreScheduleLogService } from './services/core/CoreScheduleLogService'; +import { ScheduleLogService } from './services/admin/ScheduleLogService'; // Entities import { SysConfig } from './entities/SysConfig'; @@ -116,6 +120,7 @@ import { NiuSmsTemplate } from './entities/NiuSmsTemplate'; import { UserCreateSiteLimit } from './entities/UserCreateSiteLimit'; import { WxOplatfromWeappVersion } from './entities/WxOplatfromWeappVersion'; import { SysUpgradeRecords } from './entities/SysUpgradeRecords'; +import { Channel } from '../channel/entities/Channel'; @Module({ imports: [ @@ -136,6 +141,7 @@ import { SysUpgradeRecords } from './entities/SysUpgradeRecords'; SysSchedule, SysScheduleLog, SysChannel, + Channel, SysApp, SysNoticeSmsLog, SysBackupRecords, @@ -216,10 +222,12 @@ import { SysUpgradeRecords } from './entities/SysUpgradeRecords'; CorePrinterService, CorePrinterTemplateService, CoreScheduleService, + CoreScheduleLogService, CoreSysConfigService, PrinterService, PrinterTemplateService, ScheduleService, + ScheduleLogService, ApiAttachmentService, UploadService, Base64Service, @@ -236,6 +244,8 @@ import { SysUpgradeRecords } from './entities/SysUpgradeRecords'; CommonService, CoreChannelService, CoreCommonService, + CoreUeditorService, + UeditorService, ], exports: [ ConfigService, @@ -262,10 +272,12 @@ import { SysUpgradeRecords } from './entities/SysUpgradeRecords'; CorePrinterService, CorePrinterTemplateService, CoreScheduleService, + CoreScheduleLogService, CoreSysConfigService, PrinterService, PrinterTemplateService, ScheduleService, + ScheduleLogService, ApiAttachmentService, UploadService, Base64Service, @@ -282,6 +294,8 @@ import { SysUpgradeRecords } from './entities/SysUpgradeRecords'; CommonService, CoreChannelService, CoreCommonService, + CoreUeditorService, + UeditorService, ], }) export class SysModule {} diff --git a/wwjcloud/src/common/upload/controllers/adminapi/storage.controller.ts b/wwjcloud/src/common/upload/controllers/adminapi/storage.controller.ts index 97ff17b..ac7c489 100644 --- a/wwjcloud/src/common/upload/controllers/adminapi/storage.controller.ts +++ b/wwjcloud/src/common/upload/controllers/adminapi/storage.controller.ts @@ -6,6 +6,7 @@ import { Req, Body, Query, + UnauthorizedException, } from '@nestjs/common'; import { ApiTags, @@ -42,7 +43,10 @@ export class AdminStorageController { @Roles('super', 'admin') async lists(@Req() req: any) { // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } return this.storageService.getStorageList(siteId); } @@ -60,7 +64,10 @@ export class AdminStorageController { @Req() req: any, ): Promise { // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } return this.storageService.getStorageConfig(storage_type, siteId); } @@ -74,7 +81,10 @@ export class AdminStorageController { @Roles('super', 'admin') async edit(@Body() data: SetStorageConfigDto, @Req() req: any) { // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } await this.storageService.setStorageConfig(data, siteId); return { message: 'SET_SUCCESS' }; diff --git a/wwjcloud/src/common/upload/controllers/adminapi/upload.controller.ts b/wwjcloud/src/common/upload/controllers/adminapi/upload.controller.ts index 8a77b82..d0513b8 100644 --- a/wwjcloud/src/common/upload/controllers/adminapi/upload.controller.ts +++ b/wwjcloud/src/common/upload/controllers/adminapi/upload.controller.ts @@ -9,6 +9,7 @@ import { Req, Param, Body, + UnauthorizedException, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { @@ -85,7 +86,10 @@ export class AdminUploadController { } // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const uid = req.user?.uid || 0; const userType = req.user?.userType || 'admin'; const userContext = { siteId, uid, userType }; @@ -129,7 +133,10 @@ export class AdminUploadController { } // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const uid = req.user?.uid || 0; const userType = req.user?.userType || 'admin'; const userContext = { siteId, uid, userType }; @@ -169,7 +176,10 @@ export class AdminUploadController { } // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const uid = req.user?.uid || 0; const userType = req.user?.userType || 'admin'; const userContext = { siteId, uid, userType }; @@ -186,7 +196,10 @@ export class AdminUploadController { @Roles('super', 'admin') async setUploadConfig(@Body() data: SetUploadConfigDto, @Req() req: any) { // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } await this.uploadConfigService.setUploadConfig(data, siteId); return { message: 'SET_SUCCESS' }; @@ -201,7 +214,10 @@ export class AdminUploadController { @Roles('super', 'admin') async getUploadConfig(@Req() req: any): Promise { // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } return this.uploadConfigService.getUploadConfig(siteId); } diff --git a/wwjcloud/src/common/upload/controllers/api/upload.controller.ts b/wwjcloud/src/common/upload/controllers/api/upload.controller.ts index f921a92..602a848 100644 --- a/wwjcloud/src/common/upload/controllers/api/upload.controller.ts +++ b/wwjcloud/src/common/upload/controllers/api/upload.controller.ts @@ -7,6 +7,7 @@ import { UseGuards, Req, Body, + UnauthorizedException, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { @@ -59,7 +60,10 @@ export class ApiUploadController { } // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const uid = req.user?.member_id || 0; const userType = 'member'; const userContext = { siteId, uid, userType }; @@ -94,7 +98,10 @@ export class ApiUploadController { } // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const uid = req.user?.member_id || 0; const userType = 'member'; const userContext = { siteId, uid, userType }; @@ -126,7 +133,10 @@ export class ApiUploadController { } // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const uid = req.user?.member_id || 0; const userType = 'member'; const userContext = { siteId, uid, userType }; @@ -159,7 +169,10 @@ export class ApiUploadController { } // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const uid = req.user?.member_id || 0; const userType = 'member'; const userContext = { siteId, uid, userType }; diff --git a/wwjcloud/src/common/upload/entities/Attachment.ts b/wwjcloud/src/common/upload/entities/Attachment.ts deleted file mode 100644 index b522178..0000000 --- a/wwjcloud/src/common/upload/entities/Attachment.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; - -@Entity('attachment') -export class Attachment extends BaseEntity { - @PrimaryGeneratedColumn() - attachment_id: number; - - @Column({ type: 'varchar', length: 255, comment: '文件名称' }) - file_name: string; - - @Column({ type: 'varchar', length: 255, comment: '文件路径' }) - file_path: string; - - @Column({ type: 'varchar', length: 100, comment: '文件类型' }) - file_type: string; - - @Column({ type: 'bigint', default: 0, comment: '文件大小' }) - file_size: number; - - @Column({ type: 'varchar', length: 32, comment: '文件MD5' }) - file_md5: string; - - @Column({ type: 'varchar', length: 255, comment: '文件URL' }) - file_url: string; - - @Column({ type: 'varchar', length: 50, comment: '存储类型' }) - storage_type: string; - - @Column({ type: 'varchar', length: 255, comment: '存储配置' }) - storage_config: string; - - @Column({ type: 'tinyint', default: 1, comment: '状态 1:正常 0:删除' }) - status: number; -} diff --git a/wwjcloud/src/common/upload/services/core/CoreUploadService.ts b/wwjcloud/src/common/upload/services/core/CoreUploadService.ts index 12c7a65..364db4f 100644 --- a/wwjcloud/src/common/upload/services/core/CoreUploadService.ts +++ b/wwjcloud/src/common/upload/services/core/CoreUploadService.ts @@ -1,17 +1,14 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { BaseService } from '@wwjCore/base/BaseService'; -import { Attachment } from '../../../upload/entities/Attachment'; +import { SysAttachment } from '../../../sys/entities/SysAttachment'; @Injectable() -export class CoreUploadService extends BaseService { +export class CoreUploadService { constructor( - @InjectRepository(Attachment) - private attachmentRepository: Repository, - ) { - super(attachmentRepository); - } + @InjectRepository(SysAttachment) + private attachmentRepository: Repository, + ) {} /** * 上传文件 @@ -19,15 +16,15 @@ export class CoreUploadService extends BaseService { async uploadFile(file: Express.Multer.File, body: { site_id: number; category_id?: number; type?: string }) { const attachment = this.attachmentRepository.create({ site_id: body.site_id, - file_name: file.originalname, - file_path: file.path, - file_size: file.size, - file_type: file.mimetype, - file_md5: '', // 这里应该计算MD5 - file_url: `/uploads/${file.path}`, + name: file.originalname, + real_name: file.originalname, + path: file.path, + att_size: file.size.toString(), + att_type: file.mimetype, + url: `/uploads/${file.path}`, storage_type: 'local', - storage_config: '{}', - status: 1, + cate_id: body.category_id || 0, + create_time: Math.floor(Date.now() / 1000), }); const saved = await this.attachmentRepository.save(attachment); @@ -35,12 +32,12 @@ export class CoreUploadService extends BaseService { return { success: true, data: { - file_id: saved.attachment_id, - file_name: saved.file_name, - file_path: saved.file_path, - file_url: saved.file_url, - file_size: saved.file_size, - file_type: saved.file_type, + file_id: saved.att_id, + file_name: saved.name, + file_path: saved.path, + file_url: saved.url, + file_size: saved.att_size, + file_type: saved.att_type, }, }; } @@ -49,32 +46,32 @@ export class CoreUploadService extends BaseService { * 批量上传 */ async batchUpload(files: any[], site_id: number) { - const attachments = files.map(file => + const attachments = files.map(file => this.attachmentRepository.create({ site_id, - file_name: file.originalname, - file_path: file.path, - file_size: file.size, - file_type: file.mimetype, - file_md5: '', // 这里应该计算MD5 - file_url: `/uploads/${file.path}`, + name: file.originalname, + real_name: file.originalname, + path: file.path, + dir: '', + att_size: String(file.size), + att_type: file.mimetype, + url: `/uploads/${file.path}`, storage_type: 'local', - storage_config: '{}', - status: 1, - }) + cate_id: 0, + } as Partial) ); const saved = await this.attachmentRepository.save(attachments); return { success: true, - data: saved.map(attachment => ({ - file_id: attachment.attachment_id, - file_name: attachment.file_name, - file_path: attachment.file_path, - file_url: attachment.file_url, - file_size: attachment.file_size, - file_type: attachment.file_type, + data: saved.map((attachment: SysAttachment) => ({ + file_id: attachment.att_id, + file_name: attachment.name, + file_path: attachment.path, + file_url: attachment.url, + file_size: attachment.att_size, + file_type: attachment.att_type, })), }; } @@ -94,7 +91,7 @@ export class CoreUploadService extends BaseService { * 删除文件 */ async deleteFile(file_id: number) { - const result = await this.attachmentRepository.delete({ attachment_id: file_id }); + const result = await this.attachmentRepository.delete({ att_id: file_id } as any); return { success: (result.affected || 0) > 0, message: (result.affected || 0) > 0 ? '删除成功' : '文件不存在', diff --git a/wwjcloud/src/common/upload/upload.controller.ts b/wwjcloud/src/common/upload/upload.controller.ts index 5429f83..d6f546f 100644 --- a/wwjcloud/src/common/upload/upload.controller.ts +++ b/wwjcloud/src/common/upload/upload.controller.ts @@ -7,6 +7,7 @@ import { BadRequestException, UseGuards, Req, + UnauthorizedException, } from '@nestjs/common'; import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express'; import { ApiTags, ApiConsumes, ApiBody, ApiBearerAuth } from '@nestjs/swagger'; @@ -52,7 +53,10 @@ export class UploadController { @Req() req: any, ) { // 从JWT token中获取用户信息 - const siteId = req.user?.site_id || 0; + const siteId = req.user?.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const uid = req.user?.uid || req.user?.member_id || 0; const userType = req.user?.userType || 'member'; const userContext = { siteId, uid, userType }; diff --git a/wwjcloud/src/common/wechat/controllers/api/WechatServeApiController.ts b/wwjcloud/src/common/wechat/controllers/api/WechatServeApiController.ts index 2bb1f96..d2bc6dd 100644 --- a/wwjcloud/src/common/wechat/controllers/api/WechatServeApiController.ts +++ b/wwjcloud/src/common/wechat/controllers/api/WechatServeApiController.ts @@ -6,6 +6,7 @@ import { Param, Query, UseGuards, + UnauthorizedException, } from '@nestjs/common'; import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard'; import { WechatServeApiService } from '../../services/api/WechatServeApiService'; @@ -68,7 +69,10 @@ export class WechatServeApiController { */ @Get('media') async getMedia(@Query() query: any) { - const siteId = query.site_id || 0; + const siteId = query.site_id; + if (!siteId) { + throw new UnauthorizedException('Missing site_id'); + } const mediaId = query.media_id || ''; return this.wechatServeApiService.getMedia(siteId, mediaId); } diff --git a/wwjcloud/src/common/wechat/entities/WechatFans.ts b/wwjcloud/src/common/wechat/entities/WechatFans.ts index 94710a3..55244c4 100644 --- a/wwjcloud/src/common/wechat/entities/WechatFans.ts +++ b/wwjcloud/src/common/wechat/entities/WechatFans.ts @@ -4,68 +4,72 @@ import { Column, ManyToOne, JoinColumn, + CreateDateColumn, + UpdateDateColumn, } from 'typeorm'; -import { BaseEntity } from '../../../core/base/BaseEntity'; import { Wechat } from './Wechat'; @Entity('wechat_fans') -export class WechatFans extends BaseEntity { +export class WechatFans { @PrimaryGeneratedColumn({ name: 'fans_id' }) fans_id: number; - @Column({ name: 'wechat_id', type: 'int', default: 0 }) - wechat_id: number; + @Column({ name: 'site_id', type: 'int', default: 0, comment: '站点id' }) + site_id: number; - @Column({ name: 'openid', type: 'varchar', length: 255, default: '' }) - openid: string; - - @Column({ name: 'unionid', type: 'varchar', length: 255, default: '' }) - unionid: string; - - @Column({ name: 'nickname', type: 'varchar', length: 255, default: '' }) + @Column({ name: 'nickname', type: 'varchar', length: 255, default: '', comment: '昵称' }) nickname: string; - @Column({ name: 'headimgurl', type: 'varchar', length: 1000, default: '' }) - headimgurl: string; + @Column({ name: 'avatar', type: 'varchar', length: 500, default: '', comment: '头像' }) + avatar: string; - @Column({ name: 'sex', type: 'tinyint', default: 0 }) + @Column({ name: 'sex', type: 'smallint', default: 1, comment: '性别' }) sex: number; - @Column({ name: 'country', type: 'varchar', length: 100, default: '' }) - country: string; - - @Column({ name: 'province', type: 'varchar', length: 100, default: '' }) - province: string; - - @Column({ name: 'city', type: 'varchar', length: 100, default: '' }) - city: string; - - @Column({ name: 'language', type: 'varchar', length: 50, default: '' }) + @Column({ name: 'language', type: 'varchar', length: 20, default: '', comment: '用户语言' }) language: string; - @Column({ name: 'subscribe', type: 'tinyint', default: 0 }) - subscribe: number; + @Column({ name: 'country', type: 'varchar', length: 60, default: '', comment: '国家' }) + country: string; - @Column({ name: 'subscribe_time', type: 'int', default: 0 }) - subscribe_time: number; + @Column({ name: 'province', type: 'varchar', length: 255, default: '', comment: '省' }) + province: string; - @Column({ name: 'remark', type: 'varchar', length: 500, default: '' }) - remark: string; + @Column({ name: 'city', type: 'varchar', length: 255, default: '', comment: '城市' }) + city: string; - @Column({ name: 'groupid', type: 'int', default: 0 }) + @Column({ name: 'district', type: 'varchar', length: 255, default: '', comment: '行政区/县' }) + district: string; + + @Column({ name: 'openid', type: 'varchar', length: 255, default: '', comment: '用户的标识,对当前公众号唯一' }) + openid: string; + + @Column({ name: 'unionid', type: 'varchar', length: 255, default: '', comment: '粉丝unionid' }) + unionid: string; + + @Column({ name: 'groupid', type: 'int', default: 0, comment: '粉丝所在组id' }) groupid: number; - @Column({ name: 'tagid_list', type: 'varchar', length: 500, default: '' }) - tagid_list: string; + @Column({ name: 'is_subscribe', type: 'tinyint', default: 1, comment: '是否订阅' }) + is_subscribe: number; - @Column({ name: 'subscribe_scene', type: 'varchar', length: 100, default: '' }) + @Column({ name: 'remark', type: 'varchar', length: 255, default: '', comment: '备注' }) + remark: string; + + @Column({ name: 'subscribe_time', type: 'int', default: 0, comment: '关注时间' }) + subscribe_time: number; + + @Column({ name: 'subscribe_scene', type: 'varchar', length: 100, default: '', comment: '返回用户关注的渠道来源' }) subscribe_scene: string; - @Column({ name: 'qr_scene', type: 'varchar', length: 100, default: '' }) - qr_scene: string; + @Column({ name: 'unsubscribe_time', type: 'int', default: 0, comment: '取消关注时间' }) + unsubscribe_time: number; - @Column({ name: 'qr_scene_str', type: 'varchar', length: 100, default: '' }) - qr_scene_str: string; + @Column({ name: 'app_id', type: 'int', default: 0, comment: '应用appid' }) + app_id: number; + + @CreateDateColumn({ name: 'update_time', type: 'int', default: 0, comment: '粉丝信息最后更新时间' }) + update_time: number; @ManyToOne(() => Wechat, wechat => wechat.fans) @JoinColumn({ name: 'wechat_id' }) diff --git a/wwjcloud/src/common/wechat/services/core/CoreWechatService.ts b/wwjcloud/src/common/wechat/services/core/CoreWechatService.ts index 6acc7f5..2c9b659 100644 --- a/wwjcloud/src/common/wechat/services/core/CoreWechatService.ts +++ b/wwjcloud/src/common/wechat/services/core/CoreWechatService.ts @@ -28,7 +28,7 @@ export class CoreWechatService extends BaseService { async getInfo(wechat_id: number) { return this.wechatRepository.findOne({ - where: { wechat_id }, + where: { wechat_id: wechat_id } as any, relations: ['configs', 'fans', 'media'], }); } @@ -57,13 +57,13 @@ export class CoreWechatService extends BaseService { async getFans(wechat_id: number) { return this.wechatFansRepository.find({ - where: { wechat_id }, + where: { wechat: { wechat_id: wechat_id } } as any, }); } async getMedia(wechat_id: number) { return this.wechatMediaRepository.find({ - where: { wechat_id }, + where: { wechat_id: wechat_id } as any, }); } diff --git a/wwjcloud/src/core/event/eventModule.ts b/wwjcloud/src/core/event/eventModule.ts index 31f8ce3..0d7c4c9 100644 --- a/wwjcloud/src/core/event/eventModule.ts +++ b/wwjcloud/src/core/event/eventModule.ts @@ -2,10 +2,23 @@ import { Module, Global } from '@nestjs/common'; import { EventService } from './eventService'; import { EventBusSubscriber } from './eventSubscriber'; import { EventBusPublisher } from './eventBusPublisher'; +import { DomainEventService } from './domainEventService'; @Global() @Module({ - providers: [EventService, EventBusSubscriber, EventBusPublisher], - exports: [EventService, EventBusSubscriber, EventBusPublisher], + providers: [ + EventService, + EventBusSubscriber, + EventBusPublisher, + DomainEventService, + { provide: 'IEventBus', useExisting: EventService }, + ], + exports: [ + EventService, + EventBusSubscriber, + EventBusPublisher, + DomainEventService, + { provide: 'IEventBus', useExisting: EventService } as any, + ], }) export class EventModule {} diff --git a/wwjcloud/src/core/event/eventService.ts b/wwjcloud/src/core/event/eventService.ts index 50c1850..9bdefc5 100644 --- a/wwjcloud/src/core/event/eventService.ts +++ b/wwjcloud/src/core/event/eventService.ts @@ -39,6 +39,14 @@ export class EventService { // TODO: 实现具体的订阅逻辑 } + async unsubscribe( + event: string, + handler: (data: any) => Promise, + ): Promise { + this.logger.debug(`Unsubscribing from event: ${event}`); + // TODO: 实现具体的取消订阅逻辑 + } + private generateId(): string { return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } diff --git a/wwjcloud/src/vendor/vendor.module.ts b/wwjcloud/src/vendor/vendor.module.ts index b8cb6e1..0aaff6c 100644 --- a/wwjcloud/src/vendor/vendor.module.ts +++ b/wwjcloud/src/vendor/vendor.module.ts @@ -51,14 +51,14 @@ import { PaymentAdapterRegistry } from './pay/providers/payment.provider'; KafkaProvider, RedisProvider, ...storageProviders, - PaymentAdapterRegistry, + // PaymentAdapterRegistry is provided in PayModule to avoid circular deps ], exports: [ BullQueueProvider, KafkaProvider, RedisProvider, ...storageProviders, - PaymentAdapterRegistry, + // PaymentAdapterRegistry is exported by PayModule ], }) export class VendorModule {}