保存当前开发进度:PMS模块完整实现和编译优化配置

This commit is contained in:
Xuhf 2025-05-31 19:49:27 +08:00
parent 049934932d
commit 7af5871106
164 changed files with 30617 additions and 16125 deletions

22
.cursor/settings.json Normal file
View File

@ -0,0 +1,22 @@
{
"cursor.cpp.intelliSenseEngine": "disabled",
"cursor.python.analysis.autoImportCompletions": false,
"cursor.java.completion.enabled": true,
"cursor.java.completion.maxResults": 50,
"cursor.indexing.excludePatterns": [
"**/target/**",
"**/node_modules/**",
"**/.git/**",
"**/logs/**",
"**/temp/**",
"**/*.jar",
"**/.flattened-pom.xml",
"**/ruoyi-plus-soybean/node_modules/**",
"**/ruoyi-plus-soybean/dist/**",
"**/ruoyi-plus-soybean/.temp/**"
],
"cursor.indexing.maxFileSize": "1MB",
"cursor.indexing.maxFiles": 10000,
"cursor.chat.maxTokens": 4000,
"cursor.general.enableLogging": false
}

35
.gitignore vendored
View File

@ -40,9 +40,44 @@ nbdist/
*.log
*.xml.versionsBackup
*.swp
*.md
*.ps1
*.mdc
!*/build/*.java
!*/build/*.html
!*/build/*.xml
.flattened-pom.xml
######################################################################
# Cursor优化 - 排除索引文件
*.jar
*.war
*.ear
*.class
*.pyc
*.pyo
__pycache__/
.DS_Store
Thumbs.db
# 前端构建产物
**/node_modules/
**/dist/
**/.temp/
**/.nuxt/
**/.next/
**/.vuepress/dist/
# 日志和临时文件
logs/
temp/
*.tmp
*.temp
# 开发环境文件
.env.local
.env.development.local
.env.test.local
.env.production.local

6
.mvn/jvm.config Normal file
View File

@ -0,0 +1,6 @@
-Xmx6g
-Xms3g
-XX:+UseG1GC
-XX:+UnlockExperimentalVMOptions
-Dmaven.artifact.threads=12
-Dmaven.compile.fork=true

6
.mvn/maven.config Normal file
View File

@ -0,0 +1,6 @@
-T 2C
-DskipTests=true
-Dmaven.compile.fork=true
-Dmaven.javadoc.skip=true
-Dmaven.source.skip=true
-Dmaven.test.skip=true

22
.vscode/keybindings.json vendored Normal file
View File

@ -0,0 +1,22 @@
[
{
"key": "f5",
"command": "workbench.action.tasks.runTask",
"args": "🧠 智能启动 (推荐)"
},
{
"key": "ctrl+f6",
"command": "workbench.action.tasks.runTask",
"args": "⚡ 零编译启动"
},
{
"key": "ctrl+alt+x",
"command": "workbench.action.tasks.runTask",
"args": "🛑 停止后台编译"
},
{
"key": "ctrl+alt+b",
"command": "workbench.action.tasks.runTask",
"args": "📦 PMS快速编译"
}
]

59
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,59 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "DromaraApplication",
"request": "launch",
"mainClass": "org.dromara.DromaraApplication",
"projectName": "ruoyi-admin"
},
{
"type": "java",
"name": "RuoYi Application",
"request": "launch",
"mainClass": "org.dromara.DromaraApplication",
"projectName": "ruoyi-admin",
"args": "",
"vmArgs": "-Xmx2g -Xms1g -XX:+UseG1GC -Dspring.profiles.active=dev -Dfile.encoding=UTF-8",
"env": {
"JAVA_TOOL_OPTIONS": "-Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai"
},
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"type": "java",
"name": "RuoYi Debug",
"request": "launch",
"mainClass": "org.dromara.DromaraApplication",
"projectName": "ruoyi-admin",
"args": "",
"vmArgs": "-Xmx2g -Xms1g -XX:+UseG1GC -Dspring.profiles.active=dev -Dfile.encoding=UTF-8 -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005",
"env": {
"JAVA_TOOL_OPTIONS": "-Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai"
},
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"type": "java",
"name": "Remote Debug",
"request": "attach",
"hostName": "localhost",
"port": 5005,
"projectName": "ruoyi-admin"
},
{
"type": "java",
"name": "JUnit Tests",
"request": "launch",
"mainClass": "",
"projectName": "ruoyi-pms",
"args": "",
"vmArgs": "-Dspring.profiles.active=test",
"env": {},
"console": "integratedTerminal"
}
]
}

119
.vscode/settings.json vendored
View File

@ -1,4 +1,119 @@
{
"java.compile.nullAnalysis.mode": "automatic",
"java.configuration.updateBuildConfiguration": "automatic"
"java.configuration.runtimes": [
{
"name": "JavaSE-21",
"path": "D:\\jdk",
"default": true
}
],
"java.compile.nullAnalysis.mode": "disabled",
"java.autobuild.enabled": false,
"java.maxConcurrentBuilds": 1,
"java.import.maven.enabled": false,
"java.import.gradle.enabled": false,
"maven.executable.path": "D:\\maven3.9\\bin\\mvn.cmd",
"maven.terminal.useJavaHome": true,
"maven.terminal.customEnv": [
{
"environmentVariable": "MAVEN_OPTS",
"value": "-Xmx6g -XX:+UseG1GC -Dmaven.artifact.threads=12"
},
{
"environmentVariable": "JAVA_TOOL_OPTIONS",
"value": "-Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai -XX:+UseG1GC"
}
],
"java.jdt.ls.vmargs": "-XX:+UseG1GC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx6g -Xms2g -XX:+UnlockExperimentalVMOptions",
"java.import.maven.offline": true,
"java.maven.downloadSources": false,
"java.maven.downloadJavadoc": false,
"java.referencesCodeLens.enabled": false,
"java.implementationsCodeLens.enabled": false,
"java.signatureHelp.enabled": true,
"java.contentProvider.preferred": "fernflower",
"java.server.launchMode": "Standard",
"java.sources.organizeImports.starThreshold": 99,
"java.sources.organizeImports.staticStarThreshold": 99,
"java.saveActions.organizeImports": false,
"java.completion.maxResults": 50,
"java.completion.enabled": true,
"java.configuration.updateBuildConfiguration": "disabled",
"java.configuration.checkProjectSettingsExclusions": false,
"java.project.referencedLibraries": [],
"java.project.sourcePaths": [],
"java.project.outputPath": "",
"java.dependency.autoRefresh": false,
"java.dependency.refreshDelay": 2000,
"java.dependency.packagePresentation": "flat",
"java.project.importOnFirstTimeStartup": "disabled",
"java.project.importHint": false,
"java.workspace.filter": false,
"java.clean.workspace": false,
"java.format.enabled": false,
"java.codeGeneration.hashCodeEquals.useJava7Objects": true,
"java.codeGeneration.useBlocks": true,
"java.progressReports.enabled": false,
"java.recommendations.enabled": false,
"java.references.includeAccessors": false,
"java.references.includeDecompiledSources": false,
"java.typeHierarchy.lazyLoad": true,
"java.selectionRange.enabled": false,
"java.showBuildStatusOnStart.enabled": false,
"java.silentNotification": true,
"files.exclude": {
"**/target": true,
"**/.idea": true,
"**/node_modules": true,
"**/logs": true,
"**/temp": true,
"**/.git": true,
"**/ruoyi-plus-soybean/node_modules": true,
"**/ruoyi-plus-soybean/dist": true,
"**/ruoyi-plus-soybean/.temp": true,
"**/*.jar": true,
"**/.flattened-pom.xml": true,
"**/.classpath": true,
"**/.project": true,
"**/.settings": true,
"**/bin": true
},
"search.exclude": {
"**/target": true,
"**/node_modules": true,
"**/logs": true,
"**/.git": true,
"**/ruoyi-plus-soybean/node_modules": true,
"**/*.jar": true,
"**/.flattened-pom.xml": true,
"**/.classpath": true,
"**/.project": true,
"**/.settings": true,
"**/bin": true
},
"files.watcherExclude": {
"**/target/**": true,
"**/node_modules/**": true,
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/logs/**": true,
"**/temp/**": true,
"**/ruoyi-plus-soybean/node_modules/**": true,
"**/ruoyi-plus-soybean/dist/**": true,
"**/*.jar": true,
"**/.flattened-pom.xml": true,
"**/.classpath": true,
"**/.project": true,
"**/.settings/**": true,
"**/bin/**": true
},
"java.debug.settings.onBuildFailureProceed": true,
"java.eclipse.downloadSources": false,
"java.maven.updateSnapshots": false,
"java.import.maven.disableTestClasspathFlag": true,
"files.autoSave": "off",
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {},
"extensions.autoUpdate": false,
"extensions.autoCheckUpdates": false,
"update.mode": "none"
}

177
.vscode/snippets/java.json vendored Normal file
View File

@ -0,0 +1,177 @@
{
"RuoYi Controller": {
"prefix": "rycontroller",
"body": [
"@Api(tags = \"${1:模块}管理\")",
"@RestController",
"@RequestMapping(\"/${2:module}/${3:entity}\")",
"@RequiredArgsConstructor",
"public class ${4:Entity}Controller {",
"",
" private final I${4:Entity}Service ${5:entity}Service;",
"",
" @GetMapping(\"/list\")",
" @ApiOperation(\"查询${1:模块}列表\")",
" @SaCheckPermission(\"${2:module}:${3:entity}:list\")",
" public TableDataInfo<${4:Entity}Vo> list(${4:Entity}Bo bo, PageQuery pageQuery) {",
" return ${5:entity}Service.queryPageList(bo, pageQuery);",
" }",
"",
" @GetMapping(\"/{${6:id}}\")",
" @ApiOperation(\"获取${1:模块}详细信息\")",
" @SaCheckPermission(\"${2:module}:${3:entity}:query\")",
" public R<${4:Entity}Vo> getInfo(@PathVariable Long ${6:id}) {",
" return R.ok(${5:entity}Service.queryById(${6:id}));",
" }",
"",
" @PostMapping",
" @ApiOperation(\"新增${1:模块}\")",
" @SaCheckPermission(\"${2:module}:${3:entity}:add\")",
" @Log(title = \"${1:模块}管理\", businessType = BusinessType.INSERT)",
" public R<Void> add(@Validated(AddGroup.class) @RequestBody ${4:Entity}Bo bo) {",
" return toAjax(${5:entity}Service.insertByBo(bo));",
" }",
"",
" @PutMapping",
" @ApiOperation(\"修改${1:模块}\")",
" @SaCheckPermission(\"${2:module}:${3:entity}:edit\")",
" @Log(title = \"${1:模块}管理\", businessType = BusinessType.UPDATE)",
" public R<Void> edit(@Validated(EditGroup.class) @RequestBody ${4:Entity}Bo bo) {",
" return toAjax(${5:entity}Service.updateByBo(bo));",
" }",
"",
" @DeleteMapping(\"/{${6:id}s}\")",
" @ApiOperation(\"删除${1:模块}\")",
" @SaCheckPermission(\"${2:module}:${3:entity}:remove\")",
" @Log(title = \"${1:模块}管理\", businessType = BusinessType.DELETE)",
" public R<Void> remove(@PathVariable Long[] ${6:id}s) {",
" return toAjax(${5:entity}Service.deleteWithValidByIds(List.of(${6:id}s), true));",
" }",
"",
" $0",
"}"
],
"description": "创建RuoYi Controller模板"
},
"RuoYi Service": {
"prefix": "ryservice",
"body": [
"@Service",
"@RequiredArgsConstructor",
"public class ${1:Entity}ServiceImpl implements I${1:Entity}Service {",
"",
" private final ${1:Entity}Mapper baseMapper;",
"",
" @Override",
" public TableDataInfo<${1:Entity}Vo> queryPageList(${1:Entity}Bo bo, PageQuery pageQuery) {",
" LambdaQueryWrapper<${1:Entity}> lqw = buildQueryWrapper(bo);",
" Page<${1:Entity}Vo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);",
" return TableDataInfo.build(result);",
" }",
"",
" @Override",
" public ${1:Entity}Vo queryById(Long ${2:id}) {",
" return baseMapper.selectVoById(${2:id});",
" }",
"",
" @Override",
" @Transactional(rollbackFor = Exception.class)",
" public Boolean insertByBo(${1:Entity}Bo bo) {",
" ${1:Entity} add = MapstructUtils.convert(bo, ${1:Entity}.class);",
" validEntityBeforeSave(add);",
" boolean flag = baseMapper.insert(add) > 0;",
" if (flag) {",
" bo.set${3:Id}(add.get${3:Id}());",
" }",
" return flag;",
" }",
"",
" @Override",
" @Transactional(rollbackFor = Exception.class)",
" public Boolean updateByBo(${1:Entity}Bo bo) {",
" ${1:Entity} update = MapstructUtils.convert(bo, ${1:Entity}.class);",
" validEntityBeforeSave(update);",
" return baseMapper.updateById(update) > 0;",
" }",
"",
" @Override",
" @Transactional(rollbackFor = Exception.class)",
" public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {",
" if (isValid) {",
" // 做一些业务上的校验,判断是否需要校验",
" }",
" return baseMapper.deleteByIds(ids) > 0;",
" }",
"",
" private LambdaQueryWrapper<${1:Entity}> buildQueryWrapper(${1:Entity}Bo bo) {",
" Map<String, Object> params = bo.getParams();",
" LambdaQueryWrapper<${1:Entity}> lqw = Wrappers.lambdaQuery();",
" // 添加查询条件",
" return lqw;",
" }",
"",
" private void validEntityBeforeSave(${1:Entity} entity) {",
" // 做一些数据校验,如唯一约束",
" }",
"",
" $0",
"}"
],
"description": "创建RuoYi Service实现类模板"
},
"RuoYi Entity": {
"prefix": "ryentity",
"body": [
"@Data",
"@EqualsAndHashCode(callSuper = true)",
"@TableName(\"${1:table_name}\")",
"public class ${2:Entity} extends TenantEntity {",
"",
" /**",
" * ${3:主键ID}",
" */",
" @TableId(type = IdType.ASSIGN_ID)",
" private Long ${4:id};",
"",
" $0",
"}"
],
"description": "创建RuoYi Entity模板"
},
"RuoYi BO": {
"prefix": "rybo",
"body": [
"@Data",
"@EqualsAndHashCode(callSuper = true)",
"@AutoMapper(target = ${1:Entity}.class, reverseConvertGenerate = false)",
"public class ${1:Entity}Bo extends BaseEntity {",
"",
" /**",
" * ${2:主键ID}",
" */",
" @NotNull(message = \"${2:主键ID}不能为空\", groups = { EditGroup.class })",
" private Long ${3:id};",
"",
" $0",
"}"
],
"description": "创建RuoYi BO模板"
},
"RuoYi VO": {
"prefix": "ryvo",
"body": [
"@Data",
"@AutoMapper(target = ${1:Entity}.class)",
"public class ${1:Entity}Vo {",
"",
" /**",
" * ${2:主键ID}",
" */",
" private Long ${3:id};",
"",
" $0",
"}"
],
"description": "创建RuoYi VO模板"
}
}

88
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,88 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "🧠 智能启动 (推荐)",
"type": "shell",
"command": ".\\dev-start.ps1",
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "dedicated"
},
"isBackground": true,
"problemMatcher": {
"pattern": {
"regexp": "^.*$",
"file": 1,
"location": 2,
"message": 3
},
"background": {
"activeOnStart": true,
"beginsPattern": "^.*启动应用.*",
"endsPattern": "^.*Started.*in.*seconds.*"
}
}
},
{
"label": "⚡ 零编译启动",
"type": "shell",
"command": ".\\quick-start.ps1",
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "dedicated"
},
"isBackground": true,
"problemMatcher": {
"pattern": {
"regexp": "^.*$",
"file": 1,
"location": 2,
"message": 3
},
"background": {
"activeOnStart": true,
"beginsPattern": "^.*启动应用.*",
"endsPattern": "^.*Started.*in.*seconds.*"
}
}
},
{
"label": "🛑 停止后台编译",
"type": "shell",
"command": ".\\stop-background-compile.ps1",
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
}
},
{
"label": "📦 PMS快速编译",
"type": "shell",
"command": ".\\pms-compile.ps1",
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"problemMatcher": [
"$maven-compiler-java"
]
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,8 @@
## 阶段 0: 项目初始化与理解
- [x] **阅读核心文档:**
- [x] 仔细阅读《PMS数据模型.md》完全理解PMS核心表的结构、字段定义、关系以及主键/外键/索引规范。
- [x] 仔细阅读《PMS需求.md》明确PMS核心模块 [P0] 阶段必须实现的功能需求(房态、订单核心生命周期、基础财务支付、租户级系统管理基础)。
- [x] 仔细阅读《PMS数据模型.md》(v5.7)完全理解PMS核心表的结构、字段定义、关系以及主键/外键/索引规范特别是第5节核心业务枚举值定义
- [x] 仔细阅读《PMS需求.md》(v4.3)明确PMS核心模块 [P0] 阶段必须实现的功能需求(联系人基础、房态核心、价格基础、订单核心生命周期、基础财务、系统配置基础)。
- [x] 通读《RuoYi-Vue-Plus二次开发最佳实践.md》重点关注以下章节
- Chapter 1: 引言 (文档目的, 模块化特性, **二次开发核心原则**, **Cursor使用优势**)
- Chapter 2: 环境准备与项目结构 (前后端环境, **前后端项目结构**, **代码生成器与Cursor协同**)
@ -14,275 +14,673 @@
- Chapter 6: 前后端协作规范
- Chapter 7: 代码规范与风格
- Chapter 8: 新模块添加流程与实践
- [x] **环境与工具准备:**
- [x] 确保后端开发环境 (JDK, Maven, Redis, MySQL) 符合《最佳实践》Chapter 2.1 要求。
- [x] 确保前端开发环境 (Node.js, pnpm) 符合《最佳实践》Chapter 2.1 要求。
- [x] 安装并配置好 Cursor IDE将整个 `ruoyi-vue-plus` 项目导入工作区。
- [x] (可选)在 Cursor 中为项目设置特定上下文,如关键模块路径、技术栈等,以便更好地辅助开发。
- [x] 在 Cursor 中为项目设置特定上下文,包括关键模块路径、技术栈、编码规范等,以便更好地辅助开发。
- [x] **版本控制与代码管理准备:**
- [x] 配置Git多仓库管理策略主仓库 + 子模块)
- [x] 设置upstream远程源以同步官方更新
- [x] 创建开发分支策略
- [x] 确保`.gitignore`配置正确排除target、node_modules等目录
## 阶段 1: 后端开发 - 模块搭建与核心表结构
- [ ] **创建后端Maven子模块 `ruoyi-pms`** (参考《最佳实践》Chapter 2.2, 4.2, 8.3):
- [ ] 在 `ruoyi-vue-plus/ruoyi-modules` 目录下创建新的 Maven 子模块 `ruoyi-pms`
- [ ] 配置 `ruoyi-pms/pom.xml`
- [ ] 设置 `<parent>` 指向 `ruoyi-modules`
- [ ] 添加必要的公共模块依赖 (如: `ruoyi-common-core`, `ruoyi-common-mybatis`, `ruoyi-common-web`, `ruoyi-common-satoken`, `ruoyi-common-excel`, `ruoyi-common-translate`, `ruoyi-common-tenant`)。
- [ ] 在项目根目录 `pom.xml``ruoyi-modules/pom.xml``<modules>` 部分注册 `ruoyi-pms`
- [ ] **创建后端基础包结构** (参考《最佳实践》Chapter 4.2):
- [ ] 在 `ruoyi-pms/src/main/java/` 下创建基础包,例如 `org.dromara.pms`
- [ ] 在 `org.dromara.pms` 下创建标准分层包:`controller`, `service`, `service.impl`, `mapper`, `domain` (包含 `entity`, `bo`, `vo`)。
- [ ] **数据库表创建与初始化**:
- [ ] **执行SQL脚本**: 确保已在开发数据库中执行 `script/sql/pms_tables.sql` 文件创建所有PMS相关的表。
- [ ] **验证表结构**: 对照《PMS数据模型.md》仔细检查已创建的表结构、字段类型、约束、索引是否正确。
- [ ] **验证基础数据**: 确认 `pms_core_channels``pms_finance_payment_methods` 表的基础数据已按 `pms_tables.sql` 中的`INSERT`语句正确插入。
- [ ] **集成新模块到系统**:
- [ ] (如果需要)在 `ruoyi-admin` 模块的 `application.yml` 中,确保新模块的包路径 (如 `org.dromara.pms`) 被扫描到。
- [ ] (如果需要)配置MyBatis Plus扫描新模块的Mapper XML文件路径。
- [ ] **后端国际化资源文件**:
- [ ] 在 `ruoyi-pms/src/main/resources/` 下创建 `i18n` 目录。
- [ ] 在 `i18n` 目录下创建基础的国际化属性文件,如 `messages_zh_CN.properties``messages_en_US.properties`
- [x] **创建后端Maven子模块 `ruoyi-pms`** (参考《最佳实践》Chapter 2.2, 4.2, 8.3):
- [x] 在 `ruoyi-vue-plus/ruoyi-modules` 目录下创建新的 Maven 子模块 `ruoyi-pms`
- [x] 配置 `ruoyi-pms/pom.xml`
- [x] 设置 `<parent>` 指向 `ruoyi-modules`
- [x] 添加必要的公共模块依赖 (如: `ruoyi-common-core`, `ruoyi-common-mybatis`, `ruoyi-common-web`, `ruoyi-common-satoken`, `ruoyi-common-excel`, `ruoyi-common-translate`, `ruoyi-common-tenant`)。
- [x] 在项目根目录 `pom.xml``ruoyi-modules/pom.xml``<modules>` 部分注册 `ruoyi-pms`
- [x] **创建后端基础包结构** (参考《最佳实践》Chapter 4.2):
- [x] 在 `ruoyi-pms/src/main/java/` 下创建基础包 `org.dromara.pms` (应用名: pms)。
- [x] 在 `org.dromara.pms` 下创建标准分层包:`controller`, `service`, `service.impl`, `mapper`, `domain` (包含 `entity`, `bo`, `vo`)。
- [x] **后端国际化资源文件**:
- [x] 在 `ruoyi-pms/src/main/resources/` 下创建 `i18n` 目录。
- [x] 在 `i18n` 目录下创建基础的国际化属性文件,如 `messages_zh_CN.properties``messages_en_US.properties`
- [x] **API文档配置**:
- [x] 在 `ruoyi-admin``application.yml` 中配置springdoc扫描PMS模块 (`packages-to-scan: org.dromara.pms`)
- [x] 验证Swagger UI可以显示PMS模块的API文档
- [x] **集成新模块到主项目**:
- [x] 在 `ruoyi-admin` 模块的 `pom.xml` 中添加 `ruoyi-pms` 依赖
- [x] 验证项目可以正常启动并加载PMS模块
- [x] **数据库表创建与初始化** (参考《PMS数据模型.md》v5.7):
- [x] **执行SQL脚本**: 确保已在开发数据库中执行了包含所有PMS相关表`pms_customer_contacts`, `pms_contact_tags`, `pms_contact_tag_relations` 等)的创建和初始化脚本。
- [x] **验证表结构**: 对照《PMS数据模型.md》(v5.7)仔细检查已创建的表结构、字段类型、约束(包括 `del_flag NOT NULL`)、审计字段、索引是否正确。
- [x] **验证枚举值和基础数据**: 确认联系人相关的字典数据及所有枚举值相关的表字段设计已按《PMS数据模型.md》第5节正确实现。
- [x] **Cursor辅助**: 已完成PMS联系人模块相关表结构的创建和验证。
- [x] **MyBatis Plus配置优化**:
- [x] 在 `ruoyi-pms` 模块中创建配置类,添加 `@MapperScan("org.dromara.pms.mapper")` 注解
- [x] 配置MyBatis Plus的全局配置ID生成策略、逻辑删除确保与《PMS数据模型.md》中的 `del_flag` 定义一致)
- [x] **多租户配置**: 确保 `tenant.excludes` 配置与《PMS数据模型.md》6.2.1节一致,特别是 `pms_suppliers`, `pms_partners` 的排除。
- [x] 验证数据库连接和基础CRUD操作
- [x] **基础测试验证**:
- [x] 创建简单的测试Controller验证模块正常工作
- [x] 验证包扫描、依赖注入、数据库连接等基础功能
- [x] 确保项目启动无错误,日志输出正常
- [ ] **缓存策略实现** (参考《PMS需求.md》16.2节):
- [ ] **客户标签缓存**: 实现租户级标签缓存,减少数据库查询
- [ ] **房间状态缓存**: 实现房间可用性实时缓存更新
- [ ] **价格规则缓存**: 缓存活跃的价格规则,提升计算性能
- [ ] **权限数据缓存**: 实现用户权限和门店信息缓存
- [ ] **配置缓存**: 实现系统配置信息缓存,支持热更新
- [ ] **性能优化实现** (参考《PMS需求.md》16.3节):
- [ ] **客户查询优化**: 使用复合索引支持多条件查询
- [ ] **标签关联优化**: 实现批量查询客户标签关系
- [ ] **房态查询优化**: 房间状态查询使用索引优化
- [ ] **价格计算优化**: 实现规则引擎缓存和并行计算
- [ ] **分页查询优化**: 所有列表页面支持分页和排序
- [ ] **数据安全与加密实现** (参考《PMS需求.md》15.3节):
- [ ] **敏感数据加密**: 实现客户身份证号等敏感数据AES-256加密存储
- [ ] **传输安全**: 确保所有API接口使用HTTPS/TLS 1.3加密传输
- [ ] **访问控制**: 实现基于RBAC的细粒度权限控制
- [ ] **操作审计日志**: 实现完整的操作审计日志保存180天
- [ ] **数据脱敏**: 实现敏感数据在前端的脱敏显示
## 阶段 2: 后端开发 - 核心业务功能 [P0]
**通用后端开发规范 (参考《最佳实践》Chapter 4 & 7.1):**
**通用后端开发规范 (参考《最佳实践》Chapter 4 & 7.1 及《PMS需求.md》技术要求):**
- [ ] 遵循分层架构约定 (Controller -> Service -> Mapper)。
- [ ] 严格区分 Entity, BO, VO 的职责和使用场景。
- [ ] 严格区分 Entity, BO, VO 的职责和使用场景。Entity对应《PMS数据模型.md》的表结构。
- [ ] 使用 MapStruct Plus (`@AutoMapper`) 进行对象转换。
- [ ] Service 层实现类的方法应添加 `@Transactional` 注解。
- [ ] Controller 层方法应添加 `@Log` 操作日志注解和 `@SaCheckPermission` 权限注解。
- [ ] BO 对象字段使用 JSR 303/380 注解进行参数校验。
- [ ] Controller 层方法应添加 `@Log` 操作日志注解和 `@SaCheckPermission` 权限注解。权限点参考《PMS需求.md》第13节API设计。
- [ ] BO 对象字段使用 JSR 303/380 注解进行参数校验校验规则参考《PMS需求.md》API设计中的请求体定义
- [ ] VO 对象字段按需使用 `@Translation``@Sensitive` 注解。
- [ ] **枚举处理**: 后端使用Java枚举类对应《PMS数据模型.md》第5节定义的枚举值并确保与数据库存储的 `VARCHAR(50)` 字符串值正确转换。
- [ ] **状态流转**: 在Service层实现《PMS数据模型.md》第4节定义的订单、房间等状态流转逻辑。
- [ ] **数据权限**: 严格按照《PMS数据模型.md》6.2.2节和《PMS需求.md》16.5节实现多租户和门店级数据权限。
- [ ] 编写清晰的 Javadoc 注释和行内注释。
- [ ] 使用 Cursor 辅助生成代码、分析逻辑、优化代码。
**具体功能模块开发:**
**Cursor AI协作技巧提升:**
- [ ] **代码生成提示优化**: "请Cursor根据《PMS数据模型.md》中的 `pms_customer_contacts` 表结构和《PMS需求.md》中13.1节的API规范为客户联系人模块生成符合《最佳实践》的后端Controller, Service, Mapper, Entity, BO, VO 代码框架。确保包含[P0]功能:基础联系人管理。"
- [ ] **代码审查**: "请Cursor审查我为 `PmsCoreOrderServiceImpl` 编写的订单创建逻辑,检查是否符合事务管理要求、数据校验是否全面、以及状态流转是否正确。"
- [ ] **错误诊断**: "我的 `PmsRoomRoomController` 在查询房态时返回空列表请Cursor分析代码和相关MyBatis XML找出可能的原因。日志信息如下..."
- [ ] **重构建议**: "请Cursor分析 `PmsFinanceFolioServiceImpl` 中的账单计算逻辑,是否有可优化的部分,并提供重构建议。"
- [ ] **代码生成器应用 (可选但推荐)** (参考《最佳实践》Chapter 2.4):
- [ ] 针对《PMS数据模型.md》中定义的核心表 (如 `pms_room_types`, `pms_room_rooms`, `pms_core_orders` 等),使用若依代码生成器生成初始的 Entity, Mapper, Service, Controller, BO, VO。
- [ ] **Cursor辅助**: "请Cursor分析代码生成器为 `pms_room_types` 表生成的后端代码并指出哪些部分需要根据《PMS需求.md》和《最佳实践》进行调整。"
**具体功能模块开发 ([P0] 优先级参考《PMS需求.md》和《PMS数据模型.md》):**
- [ ] **1. 房型管理 (`pms_room_types`)**:
- [ ] **Domain**: 创建/调整 `PmsRoomType`, `PmsRoomTypeBo`, `PmsRoomTypeVo`
- [ ] **Mapper**: 创建/调整 `PmsRoomTypeMapper.java` 和对应的 `PmsRoomTypeMapper.xml`
- [ ] **Service**: 创建/调整 `IPmsRoomTypeService.java``PmsRoomTypeServiceImpl.java` (实现CRUD逻辑)。
- [ ] **Controller**: 创建/调整 `PmsRoomTypeController.java` (暴露RESTful API)。
- [ ] **代码生成器应用与优化** (参考《最佳实践》Chapter 2.4):
- [ ] **准备代码生成器配置**:
- [ ] 在RuoYi管理后台配置代码生成器导入《PMS数据模型.md》定义的所有PMS核心业务表如`pms_customer_contacts`, `pms_room_types`, `pms_room_rooms`, `pms_core_orders`等)。
- [ ] 配置生成参数(包名 `org.dromara.pms`、模块名 `pms`、作者、表前缀 `pms_` 处理等)。
- [ ] 设置字段属性(是否必填、查询条件、显示类型等),特别是枚举字段的处理方式。
- [ ] **批量生成基础代码**: 针对《PMS数据模型.md》中定义的核心表生成初始CRUD代码。
- [ ] **Cursor辅助优化生成代码**:
- [ ] "请Cursor分析代码生成器为 `pms_customer_contacts` 表生成的后端代码并对比《PMS需求.md》13.1节的API定义和《PMS数据模型.md》的表结构指出哪些部分需要手动调整或补充业务逻辑如加密、唯一性校验、枚举转换。"
- [ ] "请Cursor帮我优化 `PmsRoomType.java` Entity类确保所有字段与《PMS数据模型.md》一致并为相关字段如`status`添加正确的Java枚举类型和MyBatis TypeHandler如果需要。"
- [ ] "请Cursor检查 `IPmsCoreOrderService.java` 接口是否缺少《PMS需求.md》9.1.1节[P0]核心订单生命周期管理所需的业务方法,并补充完整。"
- [ ] **2. 房间管理 (`pms_room_rooms`)**:
- [ ] **Domain**: `PmsRoomRoom`, `PmsRoomRoomBo`, `PmsRoomRoomVo`.
- [ ] **Mapper**: `PmsRoomRoomMapper.java` & XML.
- [ ] **Service**: `IPmsRoomRoomService.java` & Impl (CRUD, 更新房间状态/清洁状态逻辑).
- [ ] **Controller**: `PmsRoomRoomController.java`.
- [x] **1. 联系人管理 (`pms_customer_contacts`, `pms_contact_tags`, `pms_contact_tag_relations`)** [P0]
- [x] **Domain对象优化**:
- [x] `PmsCustomerContacts`, `PmsCustomerContactsBo`, `PmsCustomerContactsVo` (参考《PMS需求.md》13.1.1 响应体)。
- [x] `PmsContactTag`, `PmsContactTagBo`, `PmsContactTagVo`.
- [x] `PmsContactTagRelation` (通常只有Entity和BO).
- [x] 实现《PMS数据模型.md》5.1节定义的客户相关枚举 (contact_type, contact_status, gender, member_level, tag_category)。
- [x] 字段校验:`fullName`必填, `phoneNumber`唯一性 (租户内), `idNumber`加密存储。
- [x] **数据库操作层**:
- [x] `PmsCustomerContactsMapper`: 实现按姓名、电话、状态、类型、标签等查询。支持租户级数据共享。
- [x] `PmsContactTagMapper`: 支持租户级和门店级标签查询 (dept_id IS NULL 或特定值)。
- [x] **业务逻辑层**: `IPmsCustomerContactsService`, `IPmsContactTagService`
- [x] 实现客户档案创建、查询、更新、逻辑删除。
- [x] 实现客户标签的增删改查,以及客户与标签的关联/解关联。
- [x] 业务校验逻辑:如电话号码唯一性,标签权限等。
- [x] **控制器层**: `PmsCustomerContactsController`, `PmsContactTagController`
- [x] 实现《PMS需求.md》13.1节定义的客户管理API和13.2节的标签API。
- [x] 权限控制: `pms:customerContacts:list`, `add`, `edit`, `delete`, `manageTags`等。
- [ ] **3. 房间锁定 (`pms_room_locks`)**:
- [ ] **Domain**: `PmsRoomLock`, `PmsRoomLockBo`, `PmsRoomLockVo`.
- [ ] **Mapper**: `PmsRoomLockMapper.java` & XML.
- [ ] **Service**: `IPmsRoomLockService.java` & Impl (CRUD).
- [ ] **Controller**: `PmsRoomLockController.java`.
- [x] **2. 房型管理 (`pms_room_types`)** [P0]
- [x] **Domain对象**: `PmsRoomType`, `PmsRoomTypeBo`, `PmsRoomTypeVo`.
- [x] 实现 `status` 枚举。
- [x] **数据库操作**: `PmsRoomTypeMapper`. 门店级隔离。
- [x] **业务逻辑**: `IPmsRoomTypeService`. 实现房型增删改查,状态管理。
- [x] **控制器**: `PmsRoomTypeController`.
- [ ] **4. 核心订单管理 (`pms_core_orders`, `pms_core_order_items`)** (参考《PMS需求.md》4.2.2 [P0]):
- [ ] **Domain**:
- `PmsCoreOrder`, `PmsCoreOrderBo`, `PmsCoreOrderVo` (应包含订单项列表).
- `PmsCoreOrderItem`, `PmsCoreOrderItemBo`, `PmsCoreOrderItemVo`.
- [ ] **Mapper**: `PmsCoreOrderMapper`, `PmsCoreOrderItemMapper` & XMLs.
- [ ] **Service**: `IPmsCoreOrderService`, `IPmsCoreOrderItemService` & Impls (实现订单创建、查询、修改、取消、状态流转核心逻辑;订单项增删改查).
- [ ] 实现订单状态转换逻辑 (pending_confirmation -> confirmed -> checked_in -> checked_out / cancelled / no_show).
- [ ] 订单创建时关联/创建 `cmn_contacts` (基础字段)。
- [ ] 订单创建时关联 `pms_core_channels`
- [ ] 订单创建/确认时,自动创建或关联 `pms_finance_folios`
- [ ] **Controller**: `PmsCoreOrderController`.
- [x] **3. 房间管理 (`pms_room_rooms`)** [P0]
- [x] **Domain对象**: `PmsRoomRoom`, `PmsRoomRoomBo`, `PmsRoomRoomVo` (可包含房型名称等关联信息)。
- [x] 实现 `room_status`, `cleaning_status` 枚举 (参考《PMS数据模型.md》5.4节)。
- [x] **数据库操作**: `PmsRoomRoomMapper`. 门店级隔离。查询需支持房型、楼层、状态组合。
- [x] **业务逻辑**: `IPmsRoomRoomService`.
- [x] 实现房间增删改查。
- [x] 房间物理状态和清洁状态的更新与管理逻辑。
- [x] 实现《PMS数据模型.md》4.2节房间状态流转。
- [x] **控制器**: `PmsRoomRoomController`.
- [ ] **5. 订单来源渠道 (`pms_core_channels`)**:
- [ ] **Domain**: `PmsCoreChannel`, `PmsCoreChannelBo`, `PmsCoreChannelVo`.
- [ ] **Mapper**: `PmsCoreChannelMapper` & XML.
- [ ] **Service**: `IPmsCoreChannelService` & Impl (CRUD).
- [ ] **Controller**: `PmsCoreChannelController`.
- [x] **4. 房间锁定管理 (`pms_room_locks`)** [P0]
- [x] **Domain对象**: `PmsRoomLock`, `PmsRoomLockBo`, `PmsRoomLockVo`.
- [x] 实现 `lock_type` 枚举。
- [x] **业务逻辑**: `IPmsRoomLockService`. 实现房间锁定、解锁、查询,锁定期间冲突检测。
- [x] **控制器**: `PmsRoomLockController`.
- [ ] **6. 财务-账单管理 (`pms_finance_folios`)** (参考《PMS需求.md》4.2.3 [P0]):
- [ ] **Domain**: `PmsFinanceFolio`, `PmsFinanceFolioBo`, `PmsFinanceFolioVo` (应包含交易流水列表).
- [ ] **Mapper**: `PmsFinanceFolioMapper` & XML.
- [ ] **Service**: `IPmsFinanceFolioService` & Impl (CRUD, 更新账单状态, 计算余额逻辑 - 应用层计算).
- [ ] **Controller**: `PmsFinanceFolioController`.
- [ ] **房态实时推送功能** [P1]
- [ ] **WebSocket集成**: 集成RuoYi框架的WebSocket功能支持房态实时推送
- [ ] **房态变更监听**: 实现房间状态变更的事件监听机制
- [ ] **实时推送服务**: 创建房态实时推送服务,支持按门店推送
- [ ] **前端WebSocket客户端**: 实现前端WebSocket连接和房态更新处理
- [ ] **推送性能优化**: 确保房态变更推送延迟 < 1秒
- [ ] **连接管理**: 实现WebSocket连接的管理和异常处理
- [ ] **7. 财务-交易流水 (`pms_finance_transactions`)**:
- [ ] **Domain**: `PmsFinanceTransaction`, `PmsFinanceTransactionBo`, `PmsFinanceTransactionVo`.
- [ ] **Mapper**: `PmsFinanceTransactionMapper` & XML.
- [ ] **Service**: `IPmsFinanceTransactionService` & Impl (CRUD, 关联 `pms_finance_payment_methods`).
- [ ] **Controller**: `PmsFinanceTransactionController`.
- [ ] **5. 核心订单管理 (`pms_core_orders`, `pms_core_order_items`)** [P0]
- [ ] **Domain对象设计**:
- [ ] `PmsCoreOrder`, `PmsCoreOrderBo`, `PmsCoreOrderVo` (应包含订单项列表、主要联系人简要信息、预订房型及分配房间信息参考《PMS需求.md》13.5)。
- [ ] `PmsCoreOrderItem`, `PmsCoreOrderItemBo`, `PmsCoreOrderItemVo`.
- [ ] 实现 `order_status`, `order_source` 枚举 (参考《PMS数据模型.md》5.6节)。
- [ ] **复杂查询实现**: `PmsCoreOrderMapper`
- [ ] 多表关联查询(订单+订单项+房型+联系人)。
- [ ] 按日期范围、状态、门店、联系人等复合条件查询。
- [ ] **核心业务逻辑**: `IPmsCoreOrderService`
- [ ] **订单创建**: 业务校验(房间可用性、价格计算基于`pms_room_pricing_rules`、库存检查、联系人关联)。
- [ ] **订单状态流转**: 实现《PMS数据模型.md》4.1节定义的订单状态流转逻辑 (pending_confirmation -> confirmed -> checked_in -> checked_out / cancelled / no_show)。
- [ ] 订单修改和取消逻辑(特定条件下)。
- [ ] **自动创建财务账单** (`pms_finance_folios`) 基础框架。
- [ ] **房态联动**: 订单操作(创建、确认、取消、入住、退房)应触发房态更新。
- [ ] **事务管理**: 确保订单及关联操作的数据一致性。
- [ ] **控制器**: `PmsCoreOrderController`. 实现《PMS需求.md》13.5节定义的订单管理核心API。
- [ ] **8. 财务-支付方式 (`pms_finance_payment_methods`)**:
- [ ] **Domain**: `PmsFinancePaymentMethod`, `PmsFinancePaymentMethodBo`, `PmsFinancePaymentMethodVo`.
- [ ] **Mapper**: `PmsFinancePaymentMethodMapper` & XML.
- [ ] **Service**: `IPmsFinancePaymentMethodService` & Impl (CRUD).
- [ ] **Controller**: `PmsFinancePaymentMethodController`.
- [ ] **6. 订单状态历史追踪 (`pms_order_status_history`)** [P0]
- [ ] **Domain对象**: `PmsOrderStatusHistory`, `PmsOrderStatusHistoryBo`, `PmsOrderStatusHistoryVo`.
- [ ] 实现 `change_reason` 枚举。
- [ ] **业务逻辑**: `IPmsOrderStatusHistoryService`.
- [ ] 订单状态变更时自动记录历史。
- [ ] 查询订单状态变更历史。
- [ ] 支持状态回滚操作(特殊情况)。
- [ ] **控制器**: `PmsOrderStatusHistoryController`.
- [ ] **9. 财务-附加费用项目 (`pms_finance_extra_charge_items`)**:
- [ ] **Domain**: `PmsFinanceExtraChargeItem`, `PmsFinanceExtraChargeItemBo`, `PmsFinanceExtraChargeItemVo`.
- [ ] **Mapper**: `PmsFinanceExtraChargeItemMapper` & XML.
- [ ] **Service**: `IPmsFinanceExtraChargeItemService` & Impl (CRUD).
- [ ] **Controller**: `PmsFinanceExtraChargeItemController`.
- [ ] **7. 入住客人信息管理 (`pms_order_guests`)** [P1]
- [ ] **Domain对象**: `PmsOrderGuest`, `PmsOrderGuestBo`, `PmsOrderGuestVo`.
- [ ] 实现 `guest_type`, `id_type`, `age_group` 枚举。
- [ ] 支持与客户档案关联 (`contact_id` 字段)。
- [ ] **业务逻辑**: `IPmsOrderGuestService`.
- [ ] 入住客人信息管理。
- [ ] 主客人与联系人档案关联。
- [ ] 同行客人选择性关联。
- [ ] 智能档案匹配和新档案创建。
- [ ] **控制器**: `PmsOrderGuestController`.
- [ ] **10. 价格规则 (`pms_room_pricing_rules`)**:
- [ ] **Domain**: `PmsRoomPricingRule`, `PmsRoomPricingRuleBo`, `PmsRoomPricingRuleVo`.
- [ ] **Mapper**: `PmsRoomPricingRuleMapper` & XML.
- [ ] **Service**: `IPmsRoomPricingRuleService` & Impl (CRUD).
- [ ] **Controller**: `PmsRoomPricingRuleController`.
- [ ] **8. 订单来源渠道管理 (`pms_core_channels`)** [P0]
- [ ] **Domain对象**: `PmsCoreChannel`, `PmsCoreChannelBo`, `PmsCoreChannelVo`.
- [ ] 实现 `channel_type` 枚举。
- [ ] **业务逻辑**: `IPmsCoreChannelService`. 基础增删改查。门店级隔离(或按需租户级)。
- [ ] **控制器**: `PmsCoreChannelController`.
- [ ] **11. 联系人基础 (`cmn_contacts`)** (P0阶段主要为订单关联所需字段):
- [ ] **Domain**: `CmnContact`, `CmnContactBo`, `CmnContactVo` (仅包含P0阶段所需字段如姓名、电话).
- [ ] **Mapper**: `CmnContactMapper` & XML.
- [ ] **Service**: `ICmnContactService` & Impl (提供基础的联系人查询、创建接口供订单模块调用).
- [ ] **Controller**: (P0阶段可能不需要完整独立的Controller主要通过订单业务间接操作).
- [ ] **9. 财务-账单管理 (`pms_finance_folios`)** [P0]
- [ ] **Domain对象**: `PmsFinanceFolio`, `PmsFinanceFolioBo`, `PmsFinanceFolioVo` (可含交易流水列表,余额通过计算列或业务逻辑实现)。
- [ ] 实现 `folio_status` 枚举 (参考《PMS数据模型.md》5.7节)。
- [ ] **业务逻辑**: `IPmsFinanceFolioService`.
- [ ] 订单确认时自动创建账单(基础框架)。
- [ ] 查询账单、更新账单状态。
- [ ] **控制器**: `PmsFinanceFolioController`. 实现《PMS需求.md》13.6节定义的账单查询API。
- [ ] **12. 租户/部门特定配置 (`pms_tenant_settings`, `pms_mp_settings`)**:
- [ ] **Domain**: `PmsTenantSetting`, `PmsTenantSettingBo`, `PmsTenantSettingVo` & 类似的 `PmsMpSetting` 对象.
- [ ] **Mapper**: `PmsTenantSettingMapper`, `PmsMpSettingMapper` & XMLs.
- [ ] **Service**: `IPmsTenantSettingService`, `IPmsMpSettingService` & Impls (CRUD, 按 group/key 查询).
- [ ] **Controller**: `PmsTenantSettingController`, `PmsMpSettingController`.
- [ ] **10. 财务-交易流水管理 (`pms_finance_transactions`)** [P0]
- [ ] **Domain对象**: `PmsFinanceTransaction`, `PmsFinanceTransactionBo`, `PmsFinanceTransactionVo`.
- [ ] 实现 `transaction_type` 枚举。
- [ ] **业务逻辑**: `IPmsFinanceTransactionService`. 记录收款、退款等基础交易。
- [ ] **控制器**: `PmsFinanceTransactionController`. 实现《PMS需求.md》13.6节定义的记录交易API。
- [ ] **13. 租户用户设备 (`pms_tenant_user_devices`)**: (用于民宿管理小程序推送等)
- [ ] **Domain**: `PmsTenantUserDevice`, `PmsTenantUserDeviceBo`, `PmsTenantUserDeviceVo`.
- [ ] **Mapper**: `PmsTenantUserDeviceMapper` & XML.
- [ ] **Service**: `IPmsTenantUserDeviceService` & Impl (CRUD, 设备注册/更新逻辑).
- [ ] **Controller**: `PmsTenantUserDeviceController`.
- [ ] **11. 财务-支付方式管理 (`pms_finance_payment_methods`)** [P0]
- [ ] **Domain对象**: `PmsFinancePaymentMethod`, `PmsFinancePaymentMethodBo`, `PmsFinancePaymentMethodVo`.
- [ ] 实现 `method_type` 枚举。
- [ ] **业务逻辑**: `IPmsFinancePaymentMethodService`. 基础增删改查。门店级(或租户级)。
- [ ] **控制器**: `PmsFinancePaymentMethodController`.
- [ ] **API文档**:
- [ ] 为所有Controller和DTO添加清晰的Swagger/Knife4j注解 (参考《最佳实践》Chapter 8.3)。
- [x] **12. 价格管理-价格规则基础 (`pms_room_pricing_rules`)** [P0]
- [x] **Domain对象**: `PmsRoomPricingRule`, `PmsRoomPricingRuleBo`, `PmsRoomPricingRuleVo`.
- [x] 实现 `price_adjustment_type` 枚举。
- [x] 实现 `pricing_rule_status` 枚举。
- [x] 创建枚举转换器 `PriceAdjustmentTypeConverter`, `PricingRuleStatusConverter`
- [x] **业务逻辑**: `IPmsRoomPricingRuleService`.
- [x] 基础增删改查。
- [x] 价格规则优先级管理。
- [x] 规则有效性校验。
- [x] **价格计算引擎**: `IPmsPricingCalculationService`.
- [x] 实现动态价格计算逻辑。
- [x] 多规则叠加计算。
- [x] 价格计算历史记录。
- [x] 集成缓存机制优化性能。
- [x] 支持并行计算(长期住宿)。
- [x] 特殊日期价格处理。
- [x] **缓存策略实现**: `PricingCacheService`
- [x] 活跃价格规则缓存Redis + 本地缓存)。
- [x] 特殊日期价格缓存。
- [x] 房型基础价格缓存。
- [x] 价格计算结果缓存。
- [x] 缓存失效和预热机制。
- [x] **控制器**: `PmsRoomPricingRuleController`, `PmsPricingCalculationController`.
## 阶段 3: 前端开发 - 核心管理界面 [P0] (Soybean Admin Pro)
- [x] **13. 价格计算历史追踪 (`pms_pricing_calculations`)** [P0]
- [x] **Domain对象**: `PmsPricingCalculation`, `PmsPricingCalculationBo`, `PmsPricingCalculationVo`.
- [x] **业务逻辑**: `IPmsPricingCalculationService`.
- [x] 记录每次价格计算的详细过程。
- [x] 规则应用详情记录。
- [x] 历史价格查询和趋势分析。
- [x] **控制器**: `PmsPricingCalculationController`.
- [x] **14. 特殊日期价格管理 (`pms_special_date_pricing`)** [P1]
- [x] **Domain对象**: `PmsSpecialDatePricing`, `PmsSpecialDatePricingBo`, `PmsSpecialDatePricingVo`.
- [x] 实现 `date_type` 枚举 (`SpecialDateType`)。
- [x] 实现 `special_date_status` 枚举 (`SpecialDateStatus`)。
- [x] 创建枚举转换器 `SpecialDateTypeConverter`, `SpecialDateStatusConverter`
- [x] **业务逻辑**: `IPmsSpecialDatePricingService`.
- [x] 特殊日期价格设置。
- [x] 批量设置连续日期价格。
- [x] 优先级控制和规则覆盖。
- [x] 冲突检测和解决。
- [x] **控制器**: `PmsSpecialDatePricingController`.
- [ ] **15. 库存管理与房态联动 (`pms_room_inventory_snapshot`)** [P1]
- [ ] **Domain对象**: `PmsRoomInventorySnapshot`, `PmsRoomInventorySnapshotBo`, `PmsRoomInventorySnapshotVo`.
- [ ] **业务逻辑**: `IPmsRoomInventorySnapshotService`.
- [ ] 实时库存查询。
- [ ] 库存快照生成。
- [ ] 超售保护机制。
- [ ] 房态实时同步。
- [ ] **控制器**: `PmsRoomInventorySnapshotController`.
- [x] **系统配置管理模块建表语句**:
- [x] 创建 `script/sql/pms_system_tables.sql` 文件
- [x] 包含租户配置表:`pms_tenant_settings`
- [x] 包含小程序配置表:`pms_mp_settings`
- [x] 包含用户设备表:`pms_tenant_user_devices`
- [x] 确保所有表结构与《PMS数据模型.md》v5.7完全一致
- [x] **系统配置管理功能菜单创建**:
- [x] 创建 `script/sql/pms_system_menu.sql` 文件
- [x] 包含系统配置主菜单和子菜单
- [x] 包含相关权限点定义
- [x] 按照RuoYi框架的菜单结构标准创建
## 阶段 3: 数据库表结构创建与菜单配置
- [x] **订单管理模块建表语句**:
- [x] 创建 `script/sql/pms_order_tables.sql` 文件
- [x] 包含订单核心表:`pms_core_orders`, `pms_core_order_items`, `pms_core_channels`
- [x] 包含订单增强表:`pms_order_status_history`, `pms_order_guests`
- [x] 包含库存管理表:`pms_room_inventory_snapshot`
- [x] 确保所有表结构与《PMS数据模型.md》v5.7完全一致
- [x] **价格管理模块建表语句**:
- [x] 创建 `script/sql/pms_pricing_tables.sql` 文件
- [x] 包含价格规则表:`pms_room_pricing_rules`
- [x] 包含价格计算表:`pms_pricing_calculations`
- [x] 包含特殊日期价格表:`pms_special_date_pricing`
- [x] 确保所有表结构与《PMS数据模型.md》v5.7完全一致
- [x] **订单管理功能菜单创建**:
- [x] 创建 `script/sql/pms_order_menu.sql` 文件
- [x] 包含订单管理主菜单和子菜单
- [x] 包含相关权限点定义
- [x] 按照RuoYi框架的菜单结构标准创建
- [x] **价格管理功能菜单创建**:
- [x] 创建 `script/sql/pms_pricing_menu.sql` 文件
- [x] 包含价格管理主菜单和子菜单
- [x] 包含相关权限点定义
- [x] 按照RuoYi框架的菜单结构标准创建
## 阶段 4: 价格管理功能完整开发
- [x] **价格管理实体类创建**:
- [x] 创建 `PmsRoomPricingRule.java` 实体类
- [x] 创建 `PmsPricingCalculation.java` 实体类
- [x] 创建 `IPricingService.java` 核心服务接口
- [x] 包含完整的字段定义和校验注解
- [x] **价格规则管理功能**:
- [x] 实现价格规则的CRUD操作
- [x] 实现规则优先级管理
- [x] 实现规则有效性校验
- [x] 实现规则启用/禁用功能
- [x] **动态价格计算引擎**:
- [x] 实现基础价格获取
- [x] 实现多规则叠加计算逻辑
- [x] 实现价格计算缓存机制
- [x] 实现价格计算历史记录
- [x] **特殊日期价格管理**:
- [x] 实现特殊日期价格设置
- [x] 实现批量日期价格操作
- [x] 实现价格优先级控制
- [x] 实现节假日价格自动应用
- [x] **价格管理API接口**:
- [x] 实现价格查询API
- [x] 实现价格计算API
- [x] 实现价格规则管理API
- [x] 实现特殊日期价格API
- [x] **价格管理MyBatis XML映射文件**:
- [x] 创建 `PmsRoomPricingRuleMapper.xml` 映射文件
- [x] 创建 `PmsPricingCalculationMapper.xml` 映射文件
- [x] 创建 `PmsSpecialDatePricingMapper.xml` 映射文件
- [x] 实现复杂查询SQL语句
## 阶段 4.5: 系统配置管理功能完整开发
- [x] **系统配置管理实体类创建**:
- [x] 创建 `PmsTenantSetting.java` 实体类
- [x] 创建 `PmsTenantSettingBo.java``PmsTenantSettingVo.java`
- [x] 创建 `PmsTenantSettingMapper.java` 接口
- [x] 创建 `IPmsTenantSettingService.java` 服务接口
- [x] 创建 `PmsMpSetting.java` 实体类
- [x] 创建 `PmsMpSettingBo.java``PmsMpSettingVo.java`
- [x] 创建 `PmsTenantUserDevice.java` 实体类
- [x] 实现相关枚举值定义 (`SettingType` 等)
- [ ] **租户配置管理功能**:
- [ ] 实现配置项的CRUD操作
- [ ] 实现配置分组管理
- [ ] 实现租户级和门店级配置继承
- [ ] 实现敏感配置的加密存储
- [ ] 实现配置项类型验证和转换
- [ ] **配置继承与覆盖机制**:
- [ ] 实现租户级配置作为默认配置
- [ ] 实现门店级配置覆盖租户级配置
- [ ] 实现配置查询优先级逻辑
- [ ] 实现配置合并策略
- [ ] 实现配置删除后的继承恢复
- [ ] **敏感配置安全管理**:
- [ ] 实现敏感配置AES加密存储
- [ ] 实现敏感配置访问权限控制
- [ ] 实现敏感配置操作审计日志
- [ ] 实现前端敏感信息脱敏显示
- [ ] 实现敏感配置权限分级管理
- [ ] **配置模板管理功能**:
- [ ] 实现预定义配置模板创建
- [ ] 实现配置模板分类管理
- [ ] 实现配置模板一键应用功能
- [ ] 实现配置模板导入导出
- [ ] 实现配置模板版本管理和回滚
- [ ] **系统监控与审计功能**:
- [ ] 实现配置变更监控和记录
- [ ] 实现用户行为监控和分析
- [ ] 实现系统性能监控指标
- [ ] 实现安全审计日志管理
- [ ] 实现异常配置变更报警机制
- [ ] **小程序配置管理功能**:
- [ ] 实现小程序主题配置
- [ ] 实现功能开关管理
- [ ] 实现支付配置管理
- [ ] 实现通知配置管理
- [ ] 实现租户级和门店级配置
- [ ] **用户设备管理功能**:
- [ ] 实现设备注册和管理
- [ ] 实现推送令牌管理
- [ ] 实现设备状态跟踪
- [ ] 实现多设备登录控制
- [ ] 实现设备安全审计
- [ ] **系统配置API接口**:
- [ ] 实现配置查询API
- [ ] 实现配置更新API
- [ ] 实现配置批量操作API
- [ ] 实现配置导入导出API
- [ ] 实现设备管理API
- [ ] 实现配置模板管理API
- [ ] 实现系统监控API
- [ ] **系统配置前端页面**:
- [ ] 租户配置管理页面
- [ ] 门店配置管理页面
- [ ] 小程序配置页面
- [ ] 用户设备管理页面
- [ ] 配置导入导出页面
- [ ] 配置模板管理页面
- [ ] 系统监控仪表板页面
- [ ] **预定义配置项实现**:
- [ ] 预订规则配置项
- [ ] 财务参数配置项
- [ ] 界面外观配置项
- [ ] 业务流程配置项
- [ ] 小程序功能配置项
## 阶段 5: 前端开发 - 核心功能界面 [P0]
**通用前端开发规范 (参考《最佳实践》Chapter 5 & 7.2):**
- [ ] 遵循 Soybean Admin Pro 的项目结构和编码规范。
- [ ] 使用 Vue 3 Composition API + `<script setup>`
- [ ] 为 props, emits, reactive state, methods 提供 TypeScript 类型。
- [ ] 优先使用框架提供的 Hooks (`useTable`, `useForm` 等) 和 Naive UI 组件。
- [ ] 组件样式使用 scoped CSS 或 CSS Modules。
- [ ] 使用 Cursor 辅助生成组件、分析代码、实现逻辑。
- [ ] 遵循Vue3 + TypeScript + Element Plus技术栈。
- [ ] 使用Composition API和`<script setup>`
- [ ] 严格区分页面组件、业务组件、通用组件的职责。
- [ ] 使用Pinia进行状态管理按模块划分store。
- [ ] 使用VueUse提供的组合式函数提升开发效率。
- [ ] API调用统一使用封装的request方法支持TypeScript类型定义。
- [ ] 表单校验使用Element Plus的表单验证结合自定义校验规则。
- [ ] 国际化支持使用vue-i18n按模块组织翻译文件。
- [ ] 响应式设计,适配桌面端和移动端。
- [ ] 使用 Cursor 辅助生成组件、优化代码、解决问题。
**具体功能模块开发:**
**Cursor AI协作技巧提升:**
- [ ] **组件生成**: "请Cursor根据《PMS需求.md》14.1节客户管理页面设计要求生成符合《最佳实践》的Vue3客户列表组件包含筛选、分页、批量操作功能。"
- [ ] **API集成**: "请Cursor帮我为客户管理模块创建TypeScript类型定义和API调用方法对应后端《PMS需求.md》13.1节定义的接口。"
- [ ] **状态管理**: "请Cursor设计客户管理模块的Pinia store包含客户列表、标签管理、搜索状态等。"
- [ ] **表单优化**: "请Cursor优化客户信息编辑表单的校验逻辑和用户体验确保符合《PMS需求.md》的业务规则。"
**具体前端功能模块开发:**
- [ ] **前端项目结构搭建** (参考《最佳实践》Chapter 5.2):
- [ ] 在 `src/views/`下创建 `pms` 目录,并为各管理功能创建子目录 (如 `room-type`, `room`, `order`, `folio` 等)。
- [ ] 在 `src/service/api/` 下创建 `pms` 目录并为各后端Controller创建对应的 `ts` 服务文件 (如 `roomType.ts`, `order.ts`)。
- [ ] 在 `src/typings/api/` 下创建 `pms` 目录定义与后端BO/VO对应的TypeScript接口。
- [ ] 创建 `src/router/routes/modules/pms.ts` 路由配置文件。
- [ ] (可选) 在 `src/store/modules/` 下创建 `pms` 目录用于存放PMS相关的Pinia store。
- [ ] **Cursor辅助**: "请Cursor根据《最佳实践》前端项目结构为PMS模块生成基础的目录和文件占位符。"
- [ ] 在 `ruoyi-plus-soybean/src/views/` 下创建 `pms` 目录。
- [ ] 在 `pms` 目录下按功能模块创建子目录:`customer`, `room`, `order`, `finance`, `pricing`, `system`
- [ ] 在 `ruoyi-plus-soybean/src/service/api/` 下创建 `pms.ts`定义PMS相关的API调用方法。
- [ ] 在 `ruoyi-plus-soybean/src/typings/api/` 下创建 `pms.ts`定义PMS相关的TypeScript类型。
- [ ] 在 `ruoyi-plus-soybean/src/store/modules/` 下创建 `pms.ts`定义PMS相关的Pinia store。
- [ ] **1. 房型管理界面 (`src/views/pms/room-type/`)**:
- [ ] **API服务**: `src/service/api/pms/roomType.ts` (实现对后端 `PmsRoomTypeController` 的调用)。
- [ ] **类型定义**: `src/typings/api/pms/roomType.ts` (定义 `PmsRoomTypeVo` 等接口)。
- [ ] **列表页**: `index.vue` (表格展示房型列表,支持搜索、分页、新增、编辑、删除按钮)。
- [ ] **表单组件**: `components/RoomTypeForm.vue` (用于新增/编辑房型的弹窗或抽屉表单,包含字段校验)。
- [ ] **1. 客户管理前端模块** [P0]
- [ ] **客户列表页面** (`src/views/pms/customer/index.vue`):
- [ ] 实现客户列表展示,支持分页。
- [ ] 实现多条件筛选:客户类型、状态、标签、姓名、电话。
- [ ] 实现批量操作:添加标签、状态变更。
- [ ] 集成《PMS需求.md》13.1.1定义的客户查询API。
- [ ] **客户详情页面** (`src/views/pms/customer/detail.vue`):
- [ ] 显示客户完整信息,支持编辑。
- [ ] 标签管理:添加/移除标签,颜色显示。
- [ ] 住宿历史:显示租户内所有门店的住宿记录。
- [ ] 消费统计:总消费、入住次数、平均消费。
- [ ] **客户标签管理** (`src/views/pms/customer/tags.vue`):
- [ ] 标签列表管理,支持租户级和门店级标签。
- [ ] 标签创建、编辑、删除,颜色选择。
- [ ] 标签分类管理。
- [ ] **2. 房间管理界面 (`src/views/pms/room/`)**:
- [ ] **API服务**: `src/service/api/pms/room.ts`.
- [ ] **类型定义**: `src/typings/api/pms/room.ts`.
- [ ] **列表页**: `index.vue` (展示房间列表,支持按房型、状态等搜索,操作按钮)。
- [ ] **表单组件**: `components/RoomForm.vue`.
- [ ] **房态图/日历视图基础**: (《PMS需求.md》4.2.1 [P0] 网格日历视图 - 此为复杂功能P0阶段可能先实现基础列表和状态管理)
- [ ] **2. 房态管理前端模块** [P0]
- [ ] **房态总览页面** (`src/views/pms/room/status.vue`):
- [ ] 房间状态可视化:网格布局显示所有房间状态。
- [ ] 颜色编码:可用(绿色)、占用(红色)、维护(黄色)、锁定(灰色)。
- [ ] 实时更新:房态变更自动刷新。
- [ ] 快速操作:点击房间快速变更状态。
- [ ] **房型管理页面** (`src/views/pms/room/types.vue`):
- [ ] 房型列表、创建、编辑、删除。
- [ ] 房型设施配置、图片上传。
- [ ] **房间管理页面** (`src/views/pms/room/rooms.vue`):
- [ ] 房间列表、状态管理。
- [ ] 房间锁定/解锁操作。
- [ ] 清洁状态更新。
- [ ] **3. 订单管理界面 (`src/views/pms/order/`)**:
- [ ] **API服务**: `src/service/api/pms/order.ts`.
- [ ] **类型定义**: `src/typings/api/pms/order.ts`.
- [ ] **列表页**: `index.vue` (展示订单列表,支持按日期、状态、联系人等搜索)。
- [ ] **详情页/表单**: `detail.vue``components/OrderForm.vue` (用于创建/编辑/查看订单详情,包含订单项管理)。
- [ ] 实现订单状态变更操作。
- [ ] 关联联系人选择/创建。
- [ ] 关联房型/房间选择。
- [ ] **3. 订单管理前端模块** [P0]
- [ ] **订单列表页面** (`src/views/pms/order/index.vue`):
- [ ] 按门店筛选,显示当前门店订单。
- [ ] 客户信息显示:关联租户级客户档案。
- [ ] 支持快速操作:房间分配、状态变更。
- [ ] 订单状态流转可视化。
- [ ] **订单详情页面** (`src/views/pms/order/detail.vue`):
- [ ] 订单完整信息展示和编辑。
- [ ] 入住客人信息管理。
- [ ] 订单状态历史追踪。
- [ ] **订单创建页面** (`src/views/pms/order/create.vue`):
- [ ] 订单创建向导。
- [ ] 客户选择和关联。
- [ ] 房型选择和价格计算。
- [ ] **4. 财务-账单管理界面 (`src/views/pms/folio/`)**:
- [ ] **API服务**: `src/service/api/pms/folio.ts`.
- [ ] **类型定义**: `src/typings/api/pms/folio.ts`.
- [ ] **列表页/详情页**: (展示账单列表,点击可查看账单详情及交易流水)。
- [ ] **4. 价格管理前端模块** [P0]
- [ ] **价格规则管理页面** (`src/views/pms/pricing/rules.vue`):
- [ ] 规则列表:显示所有价格规则及状态。
- [ ] 规则创建向导:分步骤创建复杂规则。
- [ ] 规则优先级拖拽排序。
- [ ] 规则效果预览:显示规则应用后的价格变化。
- [ ] **特殊日期价格管理** (`src/views/pms/pricing/special-dates.vue`):
- [ ] 特殊日期价格设置。
- [ ] 批量设置连续日期价格。
- [ ] 日历视图显示特殊价格。
- [ ] **价格计算历史** (`src/views/pms/pricing/calculations.vue`):
- [ ] 价格计算历史查询。
- [ ] 计算过程详情展示。
- [ ] 价格趋势分析图表。
- [ ] **5. 财务-支付方式管理界面 (`src/views/pms/payment-method/`)**:
- [ ] **API服务**: `src/service/api/pms/paymentMethod.ts`.
- [ ] **类型定义**: `src/typings/api/pms/paymentMethod.ts`.
- [ ] **列表页**: `index.vue` (管理支付方式)。
- [ ] **表单组件**: `components/PaymentMethodForm.vue`.
- [ ] **5. 财务管理前端模块** [P0]
- [ ] **账单管理页面** (`src/views/pms/finance/folios.vue`):
- [ ] 账单列表、状态管理。
- [ ] 账单详情查看。
- [ ] 费用项目添加。
- [ ] **交易流水页面** (`src/views/pms/finance/transactions.vue`):
- [ ] 交易记录查询。
- [ ] 收款、退款操作。
- [ ] 财务报表生成。
- [ ] **6. 财务-附加费用项目管理界面 (`src/views/pms/extra-charge-item/`)**:
- [ ] **API服务**: `src/service/api/pms/extraChargeItem.ts`.
- [ ] **类型定义**: `src/typings/api/pms/extraChargeItem.ts`.
- [ ] **列表页**: `index.vue`.
- [ ] **表单组件**: `components/ExtraChargeItemForm.vue`.
## 阶段 6: 小程序端开发 - 核心管理功能 [P2]
- [ ] **7. 价格规则管理界面 (`src/views/pms/pricing-rule/`)**:
- [ ] **API服务**: `src/service/api/pms/pricingRule.ts`.
- [ ] **类型定义**: `src/typings/api/pms/pricingRule.ts`.
- [ ] **列表页**: `index.vue`.
- [ ] **表单组件**: `components/PricingRuleForm.vue`.
**小程序开发规范 (参考《最佳实践》和《PMS需求.md》17.1.1):**
- [ ] 使用微信小程序原生开发或uni-app跨平台开发
- [ ] 遵循小程序设计规范和用户体验标准
- [ ] 实现与后端API的安全对接
- [ ] 支持多租户和门店级数据隔离
- [ ] 优化小程序性能和加载速度
- [ ] **8. 租户/部门特定配置界面 (`src/views/pms/settings/`)**:
- [ ] (按需实现,可能集成到系统现有配置管理或单独页面)
**小程序核心功能模块:**
- [ ] **路由配置 (`src/router/routes/modules/pms.ts`)**:
- [ ] 为以上所有PMS管理页面配置路由。
- [ ] 配置菜单项 (名称、图标、排序、权限标识) (参考《最佳实践》Chapter 5.3)。
- [ ] **Cursor辅助**: "请Cursor根据已创建的PMS前端页面生成对应的 `pms.ts` 路由配置文件,并包含菜单定义。"
- [ ] **小程序基础框架搭建**:
- [ ] 创建小程序项目结构
- [ ] 配置小程序基础信息和权限
- [ ] 集成API请求封装和错误处理
- [ ] 实现用户登录和身份验证
- [ ] 配置多租户和门店识别机制
- [ ] **前端国际化**:
- [ ] 将所有界面上的文本添加到 `src/locales/langs/zh-CN.ts``en-US.ts` 中。
- [ ] **移动端房态管理** [P2]
- [ ] 房态总览页面:网格或列表展示房间状态
- [ ] 房间状态变更:清洁、维护、占用状态更新
- [ ] 房间锁定/解锁操作
- [ ] 实时房态同步和推送通知
- [ ] **权限控制**:
- [ ] 使用 `useAuth` Hook 和权限指令,根据后端返回的权限标识控制按钮的显示/隐藏和页面的访问。
- [ ] **移动端客户管理** [P2]
- [ ] 客户信息快速查询
- [ ] 客户基本信息查看和编辑
- [ ] 客户标签管理
- [ ] 客户入住历史查询
## 阶段 4: 民宿管理小程序 (Owner We App) [P0] - 基础功能
- [ ] **移动端订单管理** [P2]
- [ ] 订单列表查看和筛选
- [ ] 订单详情查看和编辑
- [ ] 快速办理入住/退房
- [ ] 房间分配和变更
- [ ] 订单状态更新
**技术栈**: Uni-App (参考《PMS需求.md》4.2.8)
- [ ] **移动端清洁维护** [P2]
- [ ] 清洁任务列表和分配
- [ ] 清洁状态更新和确认
- [ ] 维护任务管理
- [ ] 工作量统计和报告
- [ ] **项目搭建**: 创建 Uni-App 项目。
- [ ] **API对接**:
- [ ] 封装调用后端PMS接口的请求函数 (复用或参考前端Web的API服务)。
- [ ] 处理用户认证和token。
- [ ] **核心功能实现**:
- [ ] **房态查看**:
- [ ] 调用后端接口获取房态数据。
- [ ] 以列表或简化日历形式展示房间状态。
- [ ] **订单提醒**: (P0阶段可能为简单的订单列表按预抵/预离排序)
- [ ] 调用后端接口获取订单列表。
- [ ] **日程查看 (今日预抵/预离)**:
- [ ] 筛选并展示当日预抵和预离的订单。
- [ ] **状态处理 (简单入住/退房操作)**:
- [ ] 提供按钮或操作,调用后端接口更新订单状态为 `checked_in``checked_out`
- [ ] **数据概览 (核心收支数据)**: (P0阶段可简化如当日收款总额)
- [ ] **门店切换功能**: 如果用户关联多个门店,允许切换当前操作的门店上下文。
- [ ] **UI/UX设计**: 简洁易用,符合移动端操作习惯。
- [ ] **打包与测试**: 在微信开发者工具和真机上进行测试。
- [ ] **移动端基础价格查看** [P2]
- [ ] 房型价格查询
- [ ] 价格规则查看
- [ ] 特殊日期价格显示
## 阶段 5: 集成、测试与部署
- [ ] **移动端系统通知** [P2]
- [ ] 重要系统通知接收
- [ ] 业务告警推送
- [ ] 消息中心管理
- [ ] 推送设置管理
## 阶段 7: 集成测试与优化
- [ ] **后端集成测试**:
- [ ] 编写单元测试覆盖核心业务逻辑。
- [ ] 编写集成测试验证API接口。
- [ ] 测试多租户数据隔离。
- [ ] 测试权限控制机制。
- [ ] **前后端联调测试**:
- [ ] 验证API接口对接。
- [ ] 测试数据流转正确性。
- [ ] 测试用户操作流程。
- [ ] 性能测试和优化。
- [ ] **用户体验优化**:
- [ ] 界面响应式适配。
- [ ] 操作流程优化。
- [ ] 错误处理和提示优化。
- [ ] 国际化支持完善。
## 阶段 8: 部署与文档
- [ ] **部署准备**:
- [ ] 生产环境配置。
- [ ] 数据库迁移脚本。
- [ ] 系统监控配置。
- [ ] **后端单元测试**:
- [ ] 为核心Service层方法编写JUnit单元测试。
- [ ] **前后端联调** (参考《最佳实践》Chapter 6, 8.5):
- [ ] 逐个功能模块进行前后端接口联调,确保数据交互正确。
- [ ] **Cursor辅助**: "后端 `PmsOrderController``getOrderById` 接口返回数据格式与前端期望不一致请Cursor分析可能的原因。"
- [ ] **系统集成测试**:
- [ ] 测试PMS模块与若依基础模块 (用户、部门、租户、权限、字典等) 的集成情况。
- [ ] 测试多租户、多部门数据隔离是否正确。
- [ ] **[P0] 功能验收测试 (UAT)**:
- [ ] 根据《PMS需求.md》中[P0]功能点,逐一进行业务场景测试。
- [ ] **Bug修复与回归测试**:
- [ ] **数据库菜单与权限SQL**:
- [ ] 编写将PMS模块前端路由配置的菜单信息插入到 `sys_menu` 表的SQL脚本。
- [ ] (如果需要新的权限标识) 编写插入到 `sys_permission` (或其他权限相关表) 的SQL脚本并关联到角色。
- [ ] **文档完善**:
- [ ] 更新/创建PMS模块相关的开发文档、API文档 (确保Swagger/Knife4j是最新的)。
- [ ] **部署准备** (参考《最佳实践》Chapter 8.5):
- [ ] 后端打包 (如 `mvn package -DskipTests`)。
- [ ] 前端打包 (`pnpm build`)。
- [ ] 小程序打包。
- [ ] **部署到测试/生产环境并验证**
## 阶段 6: 持续迭代与优化 [P1+]
- [ ] 根据《PMS需求.md》中的 [P1], [P2] 优先级,规划后续迭代功能。
- [ ] **订单管理[P1]**: 订单修改、款项管理、取消退款细则、自动化通知等。
- [ ] **联系人与会员管理[P1]**: 统一联系人档案、证件管理。
- [ ] **简易报表与分析[P1]**: 核心运营报表。
- [ ] 性能优化。
- [ ] 用户体验改进。
- [ ] 安全加固。
- [ ] API文档更新。
- [ ] 用户操作手册。
- [ ] 部署运维文档。
- [ ] 开发者文档。
---
**注意**: 此ToDoList仅为初步计划具体执行时需根据实际情况灵活调整。请频繁使用Cursor进行代码生成、分析、重构和问题排查以提高开发效率和代码质量。
**重要提醒:**
1. **严格按照优先级开发**: [P0] 功能必须优先完成并测试通过后,再进行 [P1] 和 [P2] 功能开发。
2. **文档驱动开发**: 所有开发都应严格按照《PMS需求.md》v4.3和《PMS数据模型.md》v5.7的定义进行。
3. **Cursor AI协作**: 充分利用Cursor的AI能力提升开发效率和代码质量。
4. **代码质量**: 确保代码符合《最佳实践》的规范要求,包括命名、注释、结构等。
5. **测试驱动**: 每个功能模块完成后都要进行充分测试,确保功能正确性和稳定性。
- [x] **国际化翻译文件完善**:
- [x] 完善PMS模块中文翻译文件 `pms.zh-cn.ts`
- [x] 完善PMS模块英文翻译文件 `pms.en-us.ts`
- [x] 添加价格管理相关翻译 `pricingRules`, `pricingCalculations`, `specialDates`
- [x] 修复前端国际化键缺失问题
- [x] **前端主题设置优化**:
- [x] 启用面包屑导航显示
- [x] 启用标签栏显示
- [x] 启用标签栏信息缓存
- [x] 启用全屏水印显示
- [x] 设置水印文本为 "RuoYi-Vue-Plus PMS系统"
- [x] 修改菜单样式PC端不自动折叠移动端保留折叠功能
- [x] 混合模式菜单优化:在顶部菜单混合模式下点击二级菜单不自动折叠侧边栏
- [x] **菜单自动折叠问题完整修复**
- [x] 分析默认设置状态下菜单自动折叠的根本原因
- [x] 简化菜单折叠逻辑PC端完全不自动折叠移动端保留自动折叠
- [x] 移除复杂的布局模式判断,统一按设备类型处理
- [x] 确保所有布局模式下PC端菜单行为一致
- [x] 修复国际化翻译缺失问题
- [x] 修复PmsSpecialDatePricing实体类字段映射问题
- [x] **数据库字段映射问题修复**:
- [x] 修复 `specialDate` 字段映射到 `specific_date` 数据库字段
- [x] 修复 `dateName` 字段映射到 `name` 数据库字段
- [x] 添加缺失的数据库字段:`dateRangeStart`, `dateRangeEnd`, `fixedPrice`, `isRecurringYearly`, `minLengthOfStay`, `maxLengthOfStay`, `channelRestrictionsJson`
- [x] 确保实体类与数据库表结构完全匹配
- [x] **数据模型文档字段命名一致性修正**:
- [x] 更新 `pms_special_date_pricing` 表的字段定义,与实际数据库表结构保持完全一致
- [x] 修正文档中的字段名称:`special_date` → `specific_date`, `date_name``name`
- [x] 补充完整的字段定义,包括所有数据库表中的字段
- [x] 确认实体类通过 `@TableField` 注解正确映射字段名称差异
- [x] 维护数据库设计文档的权威性和准确性

395
pom-dev.xml Normal file
View File

@ -0,0 +1,395 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-vue-plus</artifactId>
<version>${revision}</version>
<name>RuoYi-Vue-Plus-Dev</name>
<url>https://gitee.com/dromara/RuoYi-Vue-Plus</url>
<description>Dromara RuoYi-Vue-Plus多租户管理系统 - 开发环境优化版本</description>
<properties>
<revision>5.3.1</revision>
<spring-boot.version>3.4.4</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
<mybatis.version>3.5.16</mybatis.version>
<springdoc.version>2.8.5</springdoc.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<easyexcel.version>4.0.3</easyexcel.version>
<velocity.version>2.3</velocity.version>
<satoken.version>1.40.0</satoken.version>
<mybatis-plus.version>3.5.11</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.35</hutool.version>
<spring-boot-admin.version>3.4.5</spring-boot-admin.version>
<redisson.version>3.45.1</redisson.version>
<lock4j.version>2.2.7</lock4j.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version>
<snailjob.version>1.4.0</snailjob.version>
<mapstruct-plus.version>1.4.6</mapstruct-plus.version>
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
<lombok.version>1.18.36</lombok.version>
<bouncycastle.version>1.76</bouncycastle.version>
<justauth.version>1.16.7</justauth.version>
<!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version>
<!-- OSS 配置 -->
<aws.sdk.version>2.28.22</aws.sdk.version>
<!-- SMS 配置 -->
<sms4j.version>3.3.4</sms4j.version>
<!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version>
<!-- 面向运行时的D-ORM依赖 -->
<anyline.version>8.7.2-20250101</anyline.version>
<!--工作流配置-->
<warm-flow.version>1.6.8</warm-flow.version>
<!-- 插件版本 -->
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
<!-- 打包默认跳过测试 -->
<skipTests>true</skipTests>
</properties>
<profiles>
<profile>
<id>dev</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active>
<logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
<activation>
<!-- 默认环境 -->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
<!-- SpringBoot的依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- hutool 的依赖配置-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- JustAuth 的依赖配置-->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${justauth.version}</version>
</dependency>
<!-- common 的依赖配置-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-bom</artifactId>
<version>${revision}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc</artifactId>
<version>${therapi-javadoc.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${satoken.version}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>${satoken.version}</version>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${satoken.version}</version>
</dependency>
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic-ds.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- sql性能分析插件 -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>${p6spy.version}</version>
</dependency>
<!-- AWS SDK for Java 2.x -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!--短信sms4j-->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
<version>${sms4j.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
<version>${lock4j.version}</version>
</dependency>
<!-- SnailJob Client -->
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-starter</artifactId>
<version>${snailjob.version}</version>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-job-core</artifactId>
<version>${snailjob.version}</version>
</dependency>
<!-- 加密包引入 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>${mapstruct-plus.version}</version>
</dependency>
<!-- 离线IP地址定位库 ip2region -->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<!-- 项目模块依赖 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-pms</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 开发环境模块配置 - 只包含必要模块 -->
<modules>
<module>ruoyi-admin</module>
<module>ruoyi-common</module>
<!-- 注释掉extend模块减少编译时间 -->
<!-- <module>ruoyi-extend</module> -->
<module>ruoyi-modules</module>
</modules>
<packaging>pom</packaging>
<!-- 构建配置 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc-scribe</artifactId>
<version>${therapi-javadoc.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>${mapstruct-plus.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${mapstruct-plus.lombok.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- 统一版本号管理 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

514
pom.xml.original Normal file
View File

@ -0,0 +1,514 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-vue-plus</artifactId>
<version>${revision}</version>
<name>RuoYi-Vue-Plus</name>
<url>https://gitee.com/dromara/RuoYi-Vue-Plus</url>
<description>Dromara RuoYi-Vue-Plus多租户管理系统</description>
<properties>
<revision>5.3.1</revision>
<spring-boot.version>3.4.4</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
<mybatis.version>3.5.16</mybatis.version>
<springdoc.version>2.8.5</springdoc.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<easyexcel.version>4.0.3</easyexcel.version>
<velocity.version>2.3</velocity.version>
<satoken.version>1.40.0</satoken.version>
<mybatis-plus.version>3.5.11</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.35</hutool.version>
<spring-boot-admin.version>3.4.5</spring-boot-admin.version>
<redisson.version>3.45.1</redisson.version>
<lock4j.version>2.2.7</lock4j.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version>
<snailjob.version>1.4.0</snailjob.version>
<mapstruct-plus.version>1.4.6</mapstruct-plus.version>
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
<lombok.version>1.18.36</lombok.version>
<bouncycastle.version>1.76</bouncycastle.version>
<justauth.version>1.16.7</justauth.version>
<!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version>
<!-- OSS 配置 -->
<aws.sdk.version>2.28.22</aws.sdk.version>
<!-- SMS 配置 -->
<sms4j.version>3.3.4</sms4j.version>
<!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version>
<!-- 面向运行时的D-ORM依赖 -->
<anyline.version>8.7.2-20250101</anyline.version>
<!--工作流配置-->
<warm-flow.version>1.6.8</warm-flow.version>
<!-- 插件版本 -->
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
<!-- 打包默认跳过测试 -->
<skipTests>true</skipTests>
</properties>
<profiles>
<profile>
<id>local</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>local</profiles.active>
<logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active>
<logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
<activation>
<!-- 默认环境 -->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<profiles.active>prod</profiles.active>
<logging.level>warn</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
</profile>
</profiles>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
<!-- SpringBoot的依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- hutool 的依赖配置-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Warm-Flow国产工作流引擎, 在线文档http://warm-flow.cn/ -->
<dependency>
<groupId>org.dromara.warm</groupId>
<artifactId>warm-flow-mybatis-plus-sb3-starter</artifactId>
<version>${warm-flow.version}</version>
</dependency>
<dependency>
<groupId>org.dromara.warm</groupId>
<artifactId>warm-flow-plugin-ui-sb-web</artifactId>
<version>${warm-flow.version}</version>
</dependency>
<!-- JustAuth 的依赖配置-->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${justauth.version}</version>
</dependency>
<!-- common 的依赖配置-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-bom</artifactId>
<version>${revision}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc</artifactId>
<version>${therapi-javadoc.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
<!-- velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${satoken.version}</version>
</dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>${satoken.version}</version>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${satoken.version}</version>
</dependency>
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic-ds.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- sql性能分析插件 -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>${p6spy.version}</version>
</dependency>
<!-- AWS SDK for Java 2.x -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!-- 将基于 Netty 的 HTTP 客户端从类路径中移除 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!--短信sms4j-->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
<version>${sms4j.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
<version>${lock4j.version}</version>
</dependency>
<!-- SnailJob Client -->
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-starter</artifactId>
<version>${snailjob.version}</version>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-job-core</artifactId>
<version>${snailjob.version}</version>
</dependency>
<!-- 加密包引入 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>${mapstruct-plus.version}</version>
</dependency>
<!-- 离线IP地址定位库 ip2region -->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-job</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-generator</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-demo</artifactId>
<version>${revision}</version>
</dependency>
<!-- 工作流模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-workflow</artifactId>
<version>${revision}</version>
</dependency>
<!-- PMS民宿管理系统模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-pms</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>ruoyi-admin</module>
<module>ruoyi-common</module>
<module>ruoyi-extend</module>
<module>ruoyi-modules</module>
</modules>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc-scribe</artifactId>
<version>${therapi-javadoc.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>${mapstruct-plus.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${mapstruct-plus.lombok.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- 单元测试使用 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
<!-- 根据打包环境执行对应的@Tag测试方法 -->
<groups>${profiles.active}</groups>
<!-- 排除标签 -->
<excludedGroups>exclude</excludedGroups>
</configuration>
</plugin>
<!-- 统一版本号管理 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<!-- 关闭过滤 -->
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<!-- 引入所有 匹配文件进行过滤 -->
<includes>
<include>application*</include>
<include>bootstrap*</include>
<include>banner*</include>
</includes>
<!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 -->
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

140
ruoyi-admin/pom-dev.xml Normal file
View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>ruoyi-admin</artifactId>
<description>
web服务入口 - 开发环境优化版本
</description>
<dependencies>
<!-- Mysql驱动包 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-social</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-ratelimiter</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId>
</dependency>
<!-- 系统模块 - 核心必需 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<!-- PMS民宿管理系统模块 - 主要开发模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-pms</artifactId>
</dependency>
<!-- 以下模块在开发环境中暂时注释,提高启动速度 -->
<!-- 任务调度模块 - 开发时可选 -->
<!--
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-job</artifactId>
</dependency>
-->
<!-- 代码生成模块 - 开发时可选 -->
<!--
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-generator</artifactId>
</dependency>
-->
<!-- demo模块 - 开发时不需要 -->
<!--
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-demo</artifactId>
</dependency>
-->
<!-- 工作流模块 - 开发时暂时不需要 -->
<!--
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-workflow</artifactId>
</dependency>
-->
<!-- Spring Boot Admin Client - 开发时可选 -->
<!--
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -3,12 +3,12 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-vue-plus</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>ruoyi-admin</artifactId>
<description>
@ -16,112 +16,57 @@
</description>
<dependencies>
<!-- Mysql驱动包 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- &lt;!&ndash; mp支持的数据库均支持 只需要增加对应的jdbc依赖即可 &ndash;&gt;-->
<!-- &lt;!&ndash; Oracle &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.jdbc</groupId>-->
<!-- <artifactId>ojdbc8</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; 兼容oracle低版本 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.nls</groupId>-->
<!-- <artifactId>orai18n</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; PostgreSql &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>org.postgresql</groupId>-->
<!-- <artifactId>postgresql</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; SqlServer &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.microsoft.sqlserver</groupId>-->
<!-- <artifactId>mssql-jdbc</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-social</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-ratelimiter</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId>
</dependency>
<!-- 使用jar包形式的稳定模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-job</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-generator</artifactId>
</dependency>
<!-- demo模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-demo</artifactId>
</dependency>
<!-- 工作流模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-workflow</artifactId>
</dependency>
<!-- PMS民宿管理系统模块 -->
<!-- 开发模块使用源码 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-pms</artifactId>
</dependency>
<!-- 必要的common模块 -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-web</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-security</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-social</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-ratelimiter</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-sms</artifactId>
</dependency>
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- skywalking 整合 logback -->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-logback-1.x</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-trace</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
</dependencies>
<build>
@ -139,21 +84,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>ruoyi-admin</artifactId>
<description>
web服务入口
</description>
<dependencies>
<!-- Mysql驱动包 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- &lt;!&ndash; mp支持的数据库均支持 只需要增加对应的jdbc依赖即可 &ndash;&gt;-->
<!-- &lt;!&ndash; Oracle &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.jdbc</groupId>-->
<!-- <artifactId>ojdbc8</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; 兼容oracle低版本 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.nls</groupId>-->
<!-- <artifactId>orai18n</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; PostgreSql &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>org.postgresql</groupId>-->
<!-- <artifactId>postgresql</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; SqlServer &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.microsoft.sqlserver</groupId>-->
<!-- <artifactId>mssql-jdbc</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-social</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-ratelimiter</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-job</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-generator</artifactId>
</dependency>
<!-- demo模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-demo</artifactId>
</dependency>
<!-- 工作流模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-workflow</artifactId>
</dependency>
<!-- PMS民宿管理系统模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-pms</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- skywalking 整合 logback -->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-logback-1.x</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-trace</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -8,8 +8,8 @@ spring.boot.admin.client:
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
username: ruoyi
password: 123456
--- # snail-job 配置
snail-job:
@ -263,3 +263,5 @@ justauth:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab

View File

@ -11,8 +11,8 @@ spring.boot.admin.client:
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
username: ruoyi
password: 123456
--- # snail-job 配置
snail-job:
@ -265,3 +265,4 @@ justauth:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab

View File

@ -35,7 +35,7 @@ captcha:
# 日志配置
logging:
level:
org.dromara: @logging.level@
org.dromara: info
org.springframework: warn
org.mybatis.spring.mapper: error
org.apache.fury: warn
@ -62,7 +62,7 @@ spring:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: @profiles.active@
active: dev
# 文件上传
servlet:
multipart:
@ -127,6 +127,9 @@ tenant:
- sys_user_role
- sys_client
- sys_oss_config
# PMS供应商合作伙伴表 (支持全局共享,排除多租户拦截器)
- pms_suppliers # 供应商信息
- pms_partners # 合作伙伴信息
# MyBatisPlus配置
# https://baomidou.com/config/
@ -281,3 +284,4 @@ warm-flow:
- 255,205,23
## 已办理
- 157,255,0

View File

@ -2,6 +2,8 @@
# MyBatisPlus配置
# https://baomidou.com/config/
mybatis-plus:
# 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper
mapperPackage: org.dromara.**.mapper
# 启动时是否检查 MyBatis XML 文件的存在,默认不检查
checkConfigLocation: false
configuration:
@ -31,3 +33,4 @@ mybatis-plus:
insertStrategy: NOT_NULL
updateStrategy: NOT_NULL
whereStrategy: NOT_NULL

View File

@ -1,66 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-oss</artifactId>
<description>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-oss</artifactId>
<description>
ruoyi-common-oss oss服务
</description>
<dependencies>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-json</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
</dependency>
<!-- AWS SDK for Java 2.x -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<exclusions>
<!-- 将基于 CRT 的 HTTP 客户端从类路径中移除 -->
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>aws-crt-client</artifactId>
</exclusion>
<!-- 将基于 Apache 的 HTTP 客户端从类路径中移除 -->
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</exclusion>
<!-- 将配置基于 URL 连接的 HTTP 客户端从类路径中移除 -->
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 将基于 Netty 的 HTTP 客户端从类路径中移除 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
<!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-json</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
</dependency>
<!-- AWS SDK for Java 2.x -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<exclusions>
<!-- 将基于 CRT 的 HTTP 客户端从类路径中移除 -->
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>aws-crt-client</artifactId>
</exclusion>
<!-- 将基于 Apache 的 HTTP 客户端从类路径中移除 -->
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</exclusion>
<!-- 将配置基于 URL 连接的 HTTP 客户端从类路径中移除 -->
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</exclusion>
</exclusions>
<version xmlns="">2.29.15</version>
</dependency>
<!-- 将基于 Netty 的 HTTP 客户端从类路径中移除 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
<version xmlns="">2.29.15</version>
</dependency>
<!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
<version xmlns="">2.29.15</version>
</dependency>
</dependencies>
</project>

View File

@ -1,46 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-satoken</artifactId>
<dependencies>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<!-- RuoYi Common Redis-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
</dependency>
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
</dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-satoken</artifactId>
<dependencies>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<!-- RuoYi Common Redis-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
</dependency>
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version xmlns="">1.39.0</version>
</dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version xmlns="">1.39.0</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,33 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-sms</artifactId>
<description>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-sms</artifactId>
<description>
ruoyi-common-sms 短信模块
</description>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
</dependency>
<!-- RuoYi Common Redis-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
<version xmlns="">3.3.2</version>
</dependency>
<!-- RuoYi Common Redis-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,34 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-social</artifactId>
<description>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-social</artifactId>
<description>
ruoyi-common-social 授权认证
</description>
<dependencies>
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-json</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${justauth.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-json</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-extend</artifactId>
<packaging>pom</packaging>
<modules>
<module>ruoyi-monitor-admin</module>
<module>ruoyi-snailjob-server</module>
</modules>
</project>

42
ruoyi-modules/pom-dev.xml Normal file
View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 开发环境模块配置 - 只包含必要模块 -->
<modules>
<!-- 系统模块 - 核心必需 -->
<module>ruoyi-system</module>
<!-- PMS模块 - 主要开发模块 -->
<module>ruoyi-pms</module>
<!-- 以下模块在开发环境中暂时注释,提高编译和启动速度 -->
<!-- demo模块 - 开发时不需要 -->
<!-- <module>ruoyi-demo</module> -->
<!-- 代码生成模块 - 需要时可以取消注释 -->
<!-- <module>ruoyi-generator</module> -->
<!-- 任务调度模块 - 需要时可以取消注释 -->
<!-- <module>ruoyi-job</module> -->
<!-- 工作流模块 - 开发时暂时不需要 -->
<!-- <module>ruoyi-workflow</module> -->
</modules>
<artifactId>ruoyi-modules</artifactId>
<packaging>pom</packaging>
<description>
ruoyi-modules 业务模块 - 开发环境优化版本
</description>
</project>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>ruoyi-demo</module>
<module>ruoyi-generator</module>
<module>ruoyi-job</module>
<module>ruoyi-pms</module>
<module>ruoyi-system</module>
<module>ruoyi-workflow</module>
</modules>
<artifactId>ruoyi-modules</artifactId>
<packaging>pom</packaging>
<description>
ruoyi-modules 业务模块
</description>
</project>

View File

@ -12,16 +12,22 @@
<artifactId>ruoyi-pms</artifactId>
<description>
民宿管理系统(Property Management System)模块
ruoyi-pms PMS酒店管理系统模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mybatis</artifactId>
@ -29,27 +35,7 @@
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-web</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-satoken</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-excel</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-translation</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-tenant</artifactId>
<artifactId>ruoyi-common-security</artifactId>
</dependency>
<dependency>
@ -57,10 +43,46 @@
<artifactId>ruoyi-common-log</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-web</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-excel</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-idempotent</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-tenant</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-encrypt</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-sensitive</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-translation</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,178 @@
package org.dromara.pms.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.pms.domain.vo.PmsContactTagRelationsVo;
import org.dromara.pms.domain.bo.PmsContactTagRelationsBo;
import org.dromara.pms.service.IPmsContactTagRelationsService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 联系人标签关联
*
* @author xuhf
* @date 2025-05-24
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/pms/contactTagRelations")
public class PmsContactTagRelationsController extends BaseController {
private final IPmsContactTagRelationsService pmsContactTagRelationsService;
/**
* 查询联系人标签关联列表
*/
@SaCheckPermission("pms:contactTagRelations:list")
@GetMapping("/list")
public TableDataInfo<PmsContactTagRelationsVo> list(PmsContactTagRelationsBo bo, PageQuery pageQuery) {
return pmsContactTagRelationsService.queryPageList(bo, pageQuery);
}
/**
* 导出联系人标签关联列表
*/
@SaCheckPermission("pms:contactTagRelations:export")
@Log(title = "联系人标签关联", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmsContactTagRelationsBo bo, HttpServletResponse response) {
List<PmsContactTagRelationsVo> list = pmsContactTagRelationsService.queryList(bo);
ExcelUtil.exportExcel(list, "联系人标签关联", PmsContactTagRelationsVo.class, response);
}
/**
* 获取联系人标签关联详细信息
*
* @param relationId 主键
*/
@SaCheckPermission("pms:contactTagRelations:query")
@GetMapping("/{relationId}")
public R<PmsContactTagRelationsVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long relationId) {
return R.ok(pmsContactTagRelationsService.queryById(relationId));
}
/**
* 新增联系人标签关联
*/
@SaCheckPermission("pms:contactTagRelations:add")
@Log(title = "联系人标签关联", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmsContactTagRelationsBo bo) {
return toAjax(pmsContactTagRelationsService.insertByBo(bo));
}
/**
* 修改联系人标签关联
*/
@SaCheckPermission("pms:contactTagRelations:edit")
@Log(title = "联系人标签关联", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmsContactTagRelationsBo bo) {
return toAjax(pmsContactTagRelationsService.updateByBo(bo));
}
/**
* 删除联系人标签关联
*
* @param relationIds 主键串
*/
@SaCheckPermission("pms:contactTagRelations:remove")
@Log(title = "联系人标签关联", businessType = BusinessType.DELETE)
@DeleteMapping("/{relationIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] relationIds) {
return toAjax(pmsContactTagRelationsService.deleteWithValidByIds(List.of(relationIds), true));
}
/**
* 根据联系人ID查询标签关联列表
*
* @param contactId 联系人ID
*/
@SaCheckPermission("pms:contactTagRelations:list")
@GetMapping("/contact/{contactId}")
public R<List<PmsContactTagRelationsVo>> getRelationsByContactId(@PathVariable Long contactId) {
List<PmsContactTagRelationsVo> list = pmsContactTagRelationsService.queryRelationsByContactId(contactId);
return R.ok(list);
}
/**
* 根据标签ID查询关联的联系人列表
*
* @param tagId 标签ID
*/
@SaCheckPermission("pms:contactTagRelations:list")
@GetMapping("/tag/{tagId}")
public R<List<PmsContactTagRelationsVo>> getRelationsByTagId(@PathVariable Long tagId) {
List<PmsContactTagRelationsVo> list = pmsContactTagRelationsService.queryRelationsByTagId(tagId);
return R.ok(list);
}
/**
* 批量保存联系人标签关联
*
* @param contactId 联系人ID
* @param tagIds 标签ID列表
*/
@SaCheckPermission("pms:contactTagRelations:edit")
@Log(title = "联系人标签关联", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/batch/{contactId}")
public R<Void> batchSaveRelations(@PathVariable Long contactId, @RequestBody List<Long> tagIds) {
return toAjax(pmsContactTagRelationsService.batchSaveRelations(contactId, tagIds));
}
/**
* 根据联系人ID删除所有标签关联
*
* @param contactId 联系人ID
*/
@SaCheckPermission("pms:contactTagRelations:remove")
@Log(title = "联系人标签关联", businessType = BusinessType.DELETE)
@DeleteMapping("/contact/{contactId}")
public R<Void> deleteByContactId(@PathVariable Long contactId) {
return toAjax(pmsContactTagRelationsService.deleteByContactId(contactId));
}
/**
* 根据标签ID删除所有关联
*
* @param tagId 标签ID
*/
@SaCheckPermission("pms:contactTagRelations:remove")
@Log(title = "联系人标签关联", businessType = BusinessType.DELETE)
@DeleteMapping("/tag/{tagId}")
public R<Void> deleteByTagId(@PathVariable Long tagId) {
return toAjax(pmsContactTagRelationsService.deleteByTagId(tagId));
}
/**
* 检查联系人和标签的关联是否存在
*
* @param contactId 联系人ID
* @param tagId 标签ID
*/
@SaCheckPermission("pms:contactTagRelations:query")
@GetMapping("/exists/{contactId}/{tagId}")
public R<Boolean> existsRelation(@PathVariable Long contactId, @PathVariable Long tagId) {
Boolean exists = pmsContactTagRelationsService.existsRelation(contactId, tagId);
return R.ok(exists);
}
}

View File

@ -0,0 +1,147 @@
package org.dromara.pms.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.pms.domain.vo.PmsContactTagsVo;
import org.dromara.pms.domain.bo.PmsContactTagsBo;
import org.dromara.pms.service.IPmsContactTagsService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 联系人标签
*
* @author xuhf
* @date 2025-05-24
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/pms/contactTags")
public class PmsContactTagsController extends BaseController {
private final IPmsContactTagsService pmsContactTagsService;
/**
* 查询联系人标签列表
*/
@SaCheckPermission("pms:contactTags:list")
@GetMapping("/list")
public TableDataInfo<PmsContactTagsVo> list(PmsContactTagsBo bo, PageQuery pageQuery) {
return pmsContactTagsService.queryPageList(bo, pageQuery);
}
/**
* 导出联系人标签列表
*/
@SaCheckPermission("pms:contactTags:export")
@Log(title = "联系人标签", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmsContactTagsBo bo, HttpServletResponse response) {
List<PmsContactTagsVo> list = pmsContactTagsService.queryList(bo);
ExcelUtil.exportExcel(list, "联系人标签", PmsContactTagsVo.class, response);
}
/**
* 获取联系人标签详细信息
*
* @param tagId 主键
*/
@SaCheckPermission("pms:contactTags:query")
@GetMapping("/{tagId}")
public R<PmsContactTagsVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long tagId) {
return R.ok(pmsContactTagsService.queryById(tagId));
}
/**
* 新增联系人标签
*/
@SaCheckPermission("pms:contactTags:add")
@Log(title = "联系人标签", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmsContactTagsBo bo) {
return toAjax(pmsContactTagsService.insertByBo(bo));
}
/**
* 修改联系人标签
*/
@SaCheckPermission("pms:contactTags:edit")
@Log(title = "联系人标签", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmsContactTagsBo bo) {
return toAjax(pmsContactTagsService.updateByBo(bo));
}
/**
* 删除联系人标签
*
* @param tagIds 主键串
*/
@SaCheckPermission("pms:contactTags:remove")
@Log(title = "联系人标签", businessType = BusinessType.DELETE)
@DeleteMapping("/{tagIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] tagIds) {
return toAjax(pmsContactTagsService.deleteWithValidByIds(List.of(tagIds), true));
}
/**
* 根据分类查询标签列表
*
* @param category 标签分类
*/
@SaCheckPermission("pms:contactTags:list")
@GetMapping("/category/{category}")
public R<List<PmsContactTagsVo>> getTagsByCategory(@PathVariable String category) {
List<PmsContactTagsVo> list = pmsContactTagsService.queryTagsByCategory(category);
return R.ok(list);
}
/**
* 查询可用的标签分类列表
*/
@SaCheckPermission("pms:contactTags:list")
@GetMapping("/categories")
public R<List<String>> getCategories() {
List<String> categories = pmsContactTagsService.queryDistinctCategories();
return R.ok(categories);
}
/**
* 根据部门ID查询标签列表
*
* @param deptId 部门ID
*/
@SaCheckPermission("pms:contactTags:list")
@GetMapping("/dept/{deptId}")
public R<List<PmsContactTagsVo>> getTagsByDeptId(@PathVariable Long deptId) {
List<PmsContactTagsVo> list = pmsContactTagsService.queryTagsByDeptId(deptId);
return R.ok(list);
}
/**
* 查询所有可用标签用于下拉选择
*/
@SaCheckPermission("pms:contactTags:list")
@GetMapping("/available")
public R<List<PmsContactTagsVo>> getAllAvailableTags() {
List<PmsContactTagsVo> list = pmsContactTagsService.queryAllAvailableTags();
return R.ok(list);
}
}

View File

@ -0,0 +1,124 @@
package org.dromara.pms.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.pms.domain.bo.PmsCustomerContactsBo;
import org.dromara.pms.domain.vo.PmsCustomerContactsVo;
import org.dromara.pms.service.IPmsCustomerContactsService;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 客户联系人Controller
*
* @author xuhf
* @date 2025-05-24
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/pms/contacts")
public class PmsCustomerContactsController extends BaseController {
private final IPmsCustomerContactsService pmsCustomerContactsService;
/**
* 查询客户联系人列表
*/
@SaCheckPermission("pms:contacts:list")
@GetMapping("/list")
public TableDataInfo<PmsCustomerContactsVo> list(PmsCustomerContactsBo bo, PageQuery pageQuery) {
return pmsCustomerContactsService.queryPageList(bo, pageQuery);
}
/**
* 导出客户联系人列表
*/
@Log(title = "客户联系人", businessType = BusinessType.EXPORT)
@SaCheckPermission("pms:contacts:export")
@PostMapping("/export")
public void export(PmsCustomerContactsBo bo, HttpServletResponse response) {
List<PmsCustomerContactsVo> list = pmsCustomerContactsService.queryList(bo);
ExcelUtil.exportExcel(list, "客户联系人", PmsCustomerContactsVo.class, response);
}
/**
* 获取客户联系人详细信息
*/
@SaCheckPermission("pms:contacts:query")
@GetMapping("/{contactId}")
public R<PmsCustomerContactsVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long contactId) {
return R.ok(pmsCustomerContactsService.queryById(contactId));
}
/**
* 新增客户联系人
*/
@Log(title = "客户联系人", businessType = BusinessType.INSERT)
@RepeatSubmit()
@SaCheckPermission("pms:contacts:add")
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmsCustomerContactsBo bo) {
return toAjax(pmsCustomerContactsService.insertByBo(bo));
}
/**
* 修改客户联系人
*/
@Log(title = "客户联系人", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@SaCheckPermission("pms:contacts:edit")
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmsCustomerContactsBo bo) {
return toAjax(pmsCustomerContactsService.updateByBo(bo));
}
/**
* 删除客户联系人
*/
@Log(title = "客户联系人", businessType = BusinessType.DELETE)
@SaCheckPermission("pms:contacts:remove")
@DeleteMapping("/{contactIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] contactIds) {
return toAjax(pmsCustomerContactsService.deleteWithValidByIds(List.of(contactIds), true));
}
/**
* 保存联系人标签关联
*
* @param contactId 联系人ID
* @param tagIds 标签ID列表
*/
@Log(title = "客户联系人标签", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@SaCheckPermission("pms:contacts:edit")
@PostMapping("/{contactId}/tags")
public R<Void> saveContactTags(@PathVariable Long contactId, @RequestBody List<Long> tagIds) {
return toAjax(pmsCustomerContactsService.saveContactTags(contactId, tagIds));
}
/**
* 查询联系人详情包含标签信息
*
* @param contactId 联系人ID
*/
@SaCheckPermission("pms:contacts:query")
@GetMapping("/{contactId}/withTags")
public R<PmsCustomerContactsVo> getInfoWithTags(@NotNull(message = "主键不能为空") @PathVariable Long contactId) {
return R.ok(pmsCustomerContactsService.queryByIdWithTags(contactId));
}
}

View File

@ -0,0 +1,240 @@
package org.dromara.pms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.pms.domain.bo.PmsPricingCalculationBo;
import org.dromara.pms.domain.vo.PmsPricingCalculationVo;
import org.dromara.pms.service.IPmsPricingCalculationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 价格计算历史Controller
*
* @author PMS
* @date 2024-12-01
*/
@Validated
@RestController
@RequestMapping("/pms/pricing/calculations")
public class PmsPricingCalculationController extends BaseController {
@Autowired
private IPmsPricingCalculationService pmsPricingCalculationService;
/**
* 查询价格计算历史列表
*/
@SaCheckPermission("pms:pricing:calculations:list")
@GetMapping("/list")
public TableDataInfo<PmsPricingCalculationVo> list(PmsPricingCalculationBo bo, PageQuery pageQuery) {
return pmsPricingCalculationService.queryPageList(bo, pageQuery);
}
/**
* 导出价格计算历史列表
*/
@SaCheckPermission("pms:pricing:calculations:export")
@Log(title = "价格计算历史", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmsPricingCalculationBo bo, HttpServletResponse response) {
List<PmsPricingCalculationVo> list = pmsPricingCalculationService.exportList(bo);
ExcelUtil.exportExcel(list, "价格计算历史", PmsPricingCalculationVo.class, response);
}
/**
* 获取价格计算历史详细信息
*/
@SaCheckPermission("pms:pricing:calculations:query")
@GetMapping("/{calculationId}")
public R<PmsPricingCalculationVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long calculationId) {
return R.ok(pmsPricingCalculationService.queryById(calculationId));
}
/**
* 新增价格计算历史
*/
@SaCheckPermission("pms:pricing:calculations:add")
@Log(title = "价格计算历史", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmsPricingCalculationBo bo) {
return toAjax(pmsPricingCalculationService.insertByBo(bo));
}
/**
* 修改价格计算历史
*/
@SaCheckPermission("pms:pricing:calculations:edit")
@Log(title = "价格计算历史", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmsPricingCalculationBo bo) {
return toAjax(pmsPricingCalculationService.updateByBo(bo));
}
/**
* 删除价格计算历史
*/
@SaCheckPermission("pms:pricing:calculations:remove")
@Log(title = "价格计算历史", businessType = BusinessType.DELETE)
@DeleteMapping("/{calculationIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] calculationIds) {
return toAjax(pmsPricingCalculationService.deleteWithValidByIds(List.of(calculationIds), true));
}
/**
* 计算房间价格
*/
@SaCheckPermission("pms:pricing:calculations:calculate")
@Log(title = "计算房间价格", businessType = BusinessType.OTHER)
@PostMapping("/calculate")
public R<Map<String, Object>> calculatePrice(@RequestBody Map<String, Object> params) {
String tenantId = (String) params.get("tenantId");
Long deptId = Long.valueOf(params.get("deptId").toString());
Long roomTypeId = Long.valueOf(params.get("roomTypeId").toString());
LocalDate checkInDate = LocalDate.parse(params.get("checkInDate").toString());
LocalDate checkOutDate = LocalDate.parse(params.get("checkOutDate").toString());
Integer numAdults = (Integer) params.get("numAdults");
Integer numChildren = (Integer) params.get("numChildren");
String channelCode = (String) params.get("channelCode");
String memberLevel = (String) params.get("memberLevel");
Integer advanceBookingDays = (Integer) params.get("advanceBookingDays");
Boolean saveHistory = (Boolean) params.getOrDefault("saveHistory", true);
Map<String, Object> result = pmsPricingCalculationService.calculatePrice(
tenantId, deptId, roomTypeId, checkInDate, checkOutDate,
numAdults, numChildren, channelCode, memberLevel, advanceBookingDays, saveHistory);
return R.ok(result);
}
/**
* 批量计算价格
*/
@SaCheckPermission("pms:pricing:calculations:calculate")
@Log(title = "批量计算价格", businessType = BusinessType.OTHER)
@PostMapping("/batch-calculate")
public R<List<Map<String, Object>>> batchCalculatePrice(@RequestBody List<PmsPricingCalculationBo> calculations) {
List<Map<String, Object>> results = pmsPricingCalculationService.batchCalculatePrice(calculations);
return R.ok(results);
}
/**
* 查询价格趋势数据
*/
@SaCheckPermission("pms:pricing:calculations:analysis")
@GetMapping("/trend")
public R<List<Map<String, Object>>> getPriceTrend(@RequestParam String tenantId,
@RequestParam Long deptId,
@RequestParam Long roomTypeId,
@RequestParam LocalDate startDate,
@RequestParam LocalDate endDate) {
List<Map<String, Object>> trend = pmsPricingCalculationService.getPriceTrend(
tenantId, deptId, roomTypeId, startDate, endDate);
return R.ok(trend);
}
/**
* 查询规则效果分析数据
*/
@SaCheckPermission("pms:pricing:calculations:analysis")
@GetMapping("/rule-effect")
public R<List<Map<String, Object>>> getRuleEffectAnalysis(@RequestParam String tenantId,
@RequestParam Long deptId,
@RequestParam Long ruleId,
@RequestParam LocalDate startDate,
@RequestParam LocalDate endDate) {
List<Map<String, Object>> analysis = pmsPricingCalculationService.getRuleEffectAnalysis(
tenantId, deptId, ruleId, startDate, endDate);
return R.ok(analysis);
}
/**
* 查询收益分析数据
*/
@SaCheckPermission("pms:pricing:calculations:analysis")
@GetMapping("/revenue-analysis")
public R<List<Map<String, Object>>> getRevenueAnalysis(@RequestParam String tenantId,
@RequestParam Long deptId,
@RequestParam LocalDate startDate,
@RequestParam LocalDate endDate) {
List<Map<String, Object>> analysis = pmsPricingCalculationService.getRevenueAnalysis(
tenantId, deptId, startDate, endDate);
return R.ok(analysis);
}
/**
* 查询平均价格
*/
@SaCheckPermission("pms:pricing:calculations:analysis")
@GetMapping("/average-price")
public R<Map<String, Object>> getAveragePrice(@RequestParam String tenantId,
@RequestParam Long deptId,
@RequestParam Long roomTypeId,
@RequestParam LocalDate startDate,
@RequestParam LocalDate endDate) {
Map<String, Object> averagePrice = pmsPricingCalculationService.getAveragePrice(
tenantId, deptId, roomTypeId, startDate, endDate);
return R.ok(averagePrice);
}
/**
* 查询价格分布统计
*/
@SaCheckPermission("pms:pricing:calculations:analysis")
@GetMapping("/price-distribution")
public R<List<Map<String, Object>>> getPriceDistribution(@RequestParam String tenantId,
@RequestParam Long deptId,
@RequestParam Long roomTypeId,
@RequestParam LocalDate startDate,
@RequestParam LocalDate endDate) {
List<Map<String, Object>> distribution = pmsPricingCalculationService.getPriceDistribution(
tenantId, deptId, roomTypeId, startDate, endDate);
return R.ok(distribution);
}
/**
* 查询渠道价格对比
*/
@SaCheckPermission("pms:pricing:calculations:analysis")
@GetMapping("/channel-comparison")
public R<List<Map<String, Object>>> getChannelPriceComparison(@RequestParam String tenantId,
@RequestParam Long deptId,
@RequestParam Long roomTypeId,
@RequestParam LocalDate startDate,
@RequestParam LocalDate endDate) {
List<Map<String, Object>> comparison = pmsPricingCalculationService.getChannelPriceComparison(
tenantId, deptId, roomTypeId, startDate, endDate);
return R.ok(comparison);
}
/**
* 清理过期的计算记录
*/
@SaCheckPermission("pms:pricing:calculations:remove")
@Log(title = "清理过期计算记录", businessType = BusinessType.DELETE)
@DeleteMapping("/clean-expired")
public R<Integer> cleanExpiredRecords(@RequestParam LocalDateTime beforeDate) {
Integer count = pmsPricingCalculationService.cleanExpiredRecords(beforeDate);
return R.ok(count);
}
}

View File

@ -0,0 +1,206 @@
package org.dromara.pms.controller;
import java.util.List;
import java.util.Date;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.pms.domain.vo.PmsRoomLockVo;
import org.dromara.pms.domain.bo.PmsRoomLockBo;
import org.dromara.pms.service.IPmsRoomLockService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* 房间锁定管理
*
* @author xuhf
* @date 2025-05-28
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/pms/roomLock")
@Tag(name = "房间锁定管理", description = "房间锁定管理")
public class PmsRoomLockController extends BaseController {
private final IPmsRoomLockService pmsRoomLockService;
/**
* 查询房间锁定管理列表
*/
@Operation(summary = "查询房间锁定管理列表")
@SaCheckPermission("pms:roomLock:list")
@GetMapping("/list")
public TableDataInfo<PmsRoomLockVo> list(PmsRoomLockBo bo, PageQuery pageQuery) {
return pmsRoomLockService.queryPageList(bo, pageQuery);
}
/**
* 导出房间锁定管理列表
*/
@Operation(summary = "导出房间锁定管理列表")
@SaCheckPermission("pms:roomLock:export")
@Log(title = "房间锁定管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmsRoomLockBo bo, HttpServletResponse response) {
List<PmsRoomLockVo> list = pmsRoomLockService.queryList(bo);
ExcelUtil.exportExcel(list, "房间锁定管理", PmsRoomLockVo.class, response);
}
/**
* 获取房间锁定管理详细信息
*/
@Operation(summary = "获取房间锁定管理详细信息")
@SaCheckPermission("pms:roomLock:query")
@GetMapping("/{lockId}")
public R<PmsRoomLockVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long lockId) {
return R.ok(pmsRoomLockService.queryById(lockId));
}
/**
* 新增房间锁定管理
*/
@Operation(summary = "新增房间锁定管理")
@SaCheckPermission("pms:roomLock:add")
@Log(title = "房间锁定管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmsRoomLockBo bo) {
return toAjax(pmsRoomLockService.insertByBo(bo));
}
/**
* 修改房间锁定管理
*/
@Operation(summary = "修改房间锁定管理")
@SaCheckPermission("pms:roomLock:edit")
@Log(title = "房间锁定管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmsRoomLockBo bo) {
return toAjax(pmsRoomLockService.updateByBo(bo));
}
/**
* 删除房间锁定管理
*/
@Operation(summary = "删除房间锁定管理")
@SaCheckPermission("pms:roomLock:remove")
@Log(title = "房间锁定管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{lockIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] lockIds) {
return toAjax(pmsRoomLockService.deleteWithValidByIds(List.of(lockIds), true));
}
/**
* 根据房间ID查询活跃的锁定记录
*/
@Operation(summary = "根据房间ID查询活跃的锁定记录")
@SaCheckPermission("pms:roomLock:query")
@GetMapping("/room/{roomId}/active")
public R<List<PmsRoomLockVo>> getActiveLocksByRoom(@PathVariable Long roomId) {
return R.ok(pmsRoomLockService.queryActiveLocksByRoomId(roomId));
}
/**
* 根据部门ID查询锁定列表
*/
@Operation(summary = "根据部门ID查询锁定列表")
@SaCheckPermission("pms:roomLock:query")
@GetMapping("/dept/{deptId}")
public R<List<PmsRoomLockVo>> listByDept(@PathVariable Long deptId) {
return R.ok(pmsRoomLockService.queryByDeptId(deptId));
}
/**
* 根据锁定类型查询锁定列表
*/
@Operation(summary = "根据锁定类型查询锁定列表")
@SaCheckPermission("pms:roomLock:query")
@GetMapping("/type")
public R<List<PmsRoomLockVo>> listByLockType(
@Parameter(description = "部门ID") @RequestParam Long deptId,
@Parameter(description = "锁定类型") @RequestParam String lockType) {
return R.ok(pmsRoomLockService.queryByLockType(deptId, lockType));
}
/**
* 查询指定时间范围内的锁定记录
*/
@Operation(summary = "查询指定时间范围内的锁定记录")
@SaCheckPermission("pms:roomLock:query")
@GetMapping("/timeRange")
public R<List<PmsRoomLockVo>> listByTimeRange(
@Parameter(description = "部门ID") @RequestParam Long deptId,
@Parameter(description = "开始时间") @RequestParam Date startTime,
@Parameter(description = "结束时间") @RequestParam Date endTime) {
return R.ok(pmsRoomLockService.queryByTimeRange(deptId, startTime, endTime));
}
/**
* 检查房间在指定时间段是否有冲突的锁定
*/
@Operation(summary = "检查房间时间冲突")
@SaCheckPermission("pms:roomLock:query")
@GetMapping("/checkConflict")
public R<Boolean> checkTimeConflict(
@Parameter(description = "房间ID") @RequestParam Long roomId,
@Parameter(description = "开始时间") @RequestParam Date startTime,
@Parameter(description = "结束时间") @RequestParam(required = false) Date endTime,
@Parameter(description = "排除的锁定ID") @RequestParam(required = false) Long excludeId) {
return R.ok(pmsRoomLockService.checkTimeConflict(roomId, startTime, endTime, excludeId));
}
/**
* 解锁房间
*/
@Operation(summary = "解锁房间")
@SaCheckPermission("pms:roomLock:unlock")
@Log(title = "房间解锁", businessType = BusinessType.UPDATE)
@PutMapping("/{lockId}/unlock")
public R<Void> unlockRoom(
@PathVariable Long lockId,
@Parameter(description = "解锁原因") @RequestParam String unlockReason) {
return toAjax(pmsRoomLockService.unlockRoom(lockId, unlockReason));
}
/**
* 批量解锁房间
*/
@Operation(summary = "批量解锁房间")
@SaCheckPermission("pms:roomLock:unlock")
@Log(title = "批量房间解锁", businessType = BusinessType.UPDATE)
@PutMapping("/batch/unlock")
public R<Void> batchUnlockRooms(
@Parameter(description = "锁定ID列表") @RequestBody List<Long> lockIds,
@Parameter(description = "解锁原因") @RequestParam String unlockReason) {
return toAjax(pmsRoomLockService.batchUnlockRooms(lockIds, unlockReason));
}
/**
* 自动过期锁定记录
*/
@Operation(summary = "自动过期锁定记录")
@SaCheckPermission("pms:roomLock:edit")
@Log(title = "自动过期锁定", businessType = BusinessType.UPDATE)
@PutMapping("/autoExpire")
public R<Void> autoExpireLocks() {
return toAjax(pmsRoomLockService.autoExpireLocks());
}
}

View File

@ -0,0 +1,178 @@
package org.dromara.pms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.pms.domain.bo.PmsRoomPricingRuleBo;
import org.dromara.pms.domain.vo.PmsRoomPricingRuleVo;
import org.dromara.pms.service.IPmsRoomPricingRuleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
/**
* 房间价格规则Controller
*
* @author PMS
* @date 2024-12-01
*/
@Validated
@RestController
@RequestMapping("/pms/pricing/rules")
public class PmsRoomPricingRuleController extends BaseController {
@Autowired
private IPmsRoomPricingRuleService pmsRoomPricingRuleService;
/**
* 查询房间价格规则列表
*/
@SaCheckPermission("pms:pricing:rules:list")
@GetMapping("/list")
public TableDataInfo<PmsRoomPricingRuleVo> list(PmsRoomPricingRuleBo bo, PageQuery pageQuery) {
return pmsRoomPricingRuleService.queryPageList(bo, pageQuery);
}
/**
* 导出房间价格规则列表
*/
@SaCheckPermission("pms:pricing:rules:export")
@Log(title = "房间价格规则", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmsRoomPricingRuleBo bo, HttpServletResponse response) {
List<PmsRoomPricingRuleVo> list = pmsRoomPricingRuleService.exportList(bo);
ExcelUtil.exportExcel(list, "房间价格规则", PmsRoomPricingRuleVo.class, response);
}
/**
* 获取房间价格规则详细信息
*/
@SaCheckPermission("pms:pricing:rules:query")
@GetMapping("/{ruleId}")
public R<PmsRoomPricingRuleVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long ruleId) {
return R.ok(pmsRoomPricingRuleService.queryById(ruleId));
}
/**
* 新增房间价格规则
*/
@SaCheckPermission("pms:pricing:rules:add")
@Log(title = "房间价格规则", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmsRoomPricingRuleBo bo) {
return toAjax(pmsRoomPricingRuleService.insertByBo(bo));
}
/**
* 修改房间价格规则
*/
@SaCheckPermission("pms:pricing:rules:edit")
@Log(title = "房间价格规则", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmsRoomPricingRuleBo bo) {
return toAjax(pmsRoomPricingRuleService.updateByBo(bo));
}
/**
* 删除房间价格规则
*/
@SaCheckPermission("pms:pricing:rules:remove")
@Log(title = "房间价格规则", businessType = BusinessType.DELETE)
@DeleteMapping("/{ruleIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ruleIds) {
return toAjax(pmsRoomPricingRuleService.deleteWithValidByIds(List.of(ruleIds), true));
}
/**
* 启用价格规则
*/
@SaCheckPermission("pms:pricing:rules:edit")
@Log(title = "启用价格规则", businessType = BusinessType.UPDATE)
@PutMapping("/{ruleId}/enable")
public R<Void> enableRule(@NotNull(message = "规则ID不能为空") @PathVariable Long ruleId) {
return toAjax(pmsRoomPricingRuleService.enableRule(ruleId));
}
/**
* 禁用价格规则
*/
@SaCheckPermission("pms:pricing:rules:edit")
@Log(title = "禁用价格规则", businessType = BusinessType.UPDATE)
@PutMapping("/{ruleId}/disable")
public R<Void> disableRule(@NotNull(message = "规则ID不能为空") @PathVariable Long ruleId) {
return toAjax(pmsRoomPricingRuleService.disableRule(ruleId));
}
/**
* 复制价格规则
*/
@SaCheckPermission("pms:pricing:rules:add")
@Log(title = "复制价格规则", businessType = BusinessType.INSERT)
@PostMapping("/{ruleId}/copy")
public R<Void> copyRule(@NotNull(message = "规则ID不能为空") @PathVariable Long ruleId,
@RequestParam String newName) {
return toAjax(pmsRoomPricingRuleService.copyRule(ruleId, newName));
}
/**
* 批量更新规则状态
*/
@SaCheckPermission("pms:pricing:rules:edit")
@Log(title = "批量更新规则状态", businessType = BusinessType.UPDATE)
@PutMapping("/batch/status")
public R<Void> batchUpdateStatus(@RequestBody Map<String, Object> params) {
List<Long> ruleIds = (List<Long>) params.get("ruleIds");
String status = (String) params.get("status");
return toAjax(pmsRoomPricingRuleService.batchUpdateStatus(ruleIds, status));
}
/**
* 检查规则冲突
*/
@SaCheckPermission("pms:pricing:rules:query")
@PostMapping("/check-conflict")
public R<Boolean> checkRuleConflict(@RequestBody PmsRoomPricingRuleBo bo) {
return R.ok(pmsRoomPricingRuleService.checkRuleConflict(bo));
}
/**
* 查询有效的价格规则
*/
@SaCheckPermission("pms:pricing:rules:query")
@GetMapping("/active")
public R<List<PmsRoomPricingRuleVo>> getActiveRules(@RequestParam String tenantId,
@RequestParam Long deptId) {
return R.ok(pmsRoomPricingRuleService.getActiveRules(tenantId, deptId)
.stream()
.map(rule -> {
PmsRoomPricingRuleVo vo = new PmsRoomPricingRuleVo();
vo.setRuleId(rule.getRuleId());
vo.setName(rule.getName());
vo.setDescription(rule.getDescription());
vo.setPriceAdjustmentType(rule.getPriceAdjustmentType());
vo.setAdjustmentValue(rule.getAdjustmentValue());
vo.setPriority(rule.getPriority());
vo.setStatus(rule.getStatus());
return vo;
})
.toList());
}
}

View File

@ -0,0 +1,196 @@
package org.dromara.pms.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.pms.domain.vo.PmsRoomRoomVo;
import org.dromara.pms.domain.bo.PmsRoomRoomBo;
import org.dromara.pms.service.IPmsRoomRoomService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* 房间管理
*
* @author xuhf
* @date 2025-05-28
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/pms/room")
@Tag(name = "房间管理", description = "房间管理")
public class PmsRoomRoomController extends BaseController {
private final IPmsRoomRoomService pmsRoomRoomService;
/**
* 查询房间管理列表
*/
@Operation(summary = "查询房间管理列表")
@SaCheckPermission("pms:room:list")
@GetMapping("/list")
public TableDataInfo<PmsRoomRoomVo> list(PmsRoomRoomBo bo, PageQuery pageQuery) {
return pmsRoomRoomService.queryPageList(bo, pageQuery);
}
/**
* 导出房间管理列表
*/
@Operation(summary = "导出房间管理列表")
@SaCheckPermission("pms:room:export")
@Log(title = "房间管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmsRoomRoomBo bo, HttpServletResponse response) {
List<PmsRoomRoomVo> list = pmsRoomRoomService.queryList(bo);
ExcelUtil.exportExcel(list, "房间管理", PmsRoomRoomVo.class, response);
}
/**
* 获取房间管理详细信息
*/
@Operation(summary = "获取房间管理详细信息")
@SaCheckPermission("pms:room:query")
@GetMapping("/{roomId}")
public R<PmsRoomRoomVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long roomId) {
return R.ok(pmsRoomRoomService.queryById(roomId));
}
/**
* 新增房间管理
*/
@Operation(summary = "新增房间管理")
@SaCheckPermission("pms:room:add")
@Log(title = "房间管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmsRoomRoomBo bo) {
return toAjax(pmsRoomRoomService.insertByBo(bo));
}
/**
* 修改房间管理
*/
@Operation(summary = "修改房间管理")
@SaCheckPermission("pms:room:edit")
@Log(title = "房间管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmsRoomRoomBo bo) {
return toAjax(pmsRoomRoomService.updateByBo(bo));
}
/**
* 删除房间管理
*/
@Operation(summary = "删除房间管理")
@SaCheckPermission("pms:room:remove")
@Log(title = "房间管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{roomIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] roomIds) {
return toAjax(pmsRoomRoomService.deleteWithValidByIds(List.of(roomIds), true));
}
/**
* 根据房型ID查询房间列表
*/
@Operation(summary = "根据房型ID查询房间列表")
@SaCheckPermission("pms:room:query")
@GetMapping("/roomType/{roomTypeId}")
public R<List<PmsRoomRoomVo>> listByRoomType(@PathVariable Long roomTypeId) {
return R.ok(pmsRoomRoomService.queryByRoomTypeId(roomTypeId));
}
/**
* 根据部门ID查询房间列表
*/
@Operation(summary = "根据部门ID查询房间列表")
@SaCheckPermission("pms:room:query")
@GetMapping("/dept/{deptId}")
public R<List<PmsRoomRoomVo>> listByDept(@PathVariable Long deptId) {
return R.ok(pmsRoomRoomService.queryByDeptId(deptId));
}
/**
* 根据状态查询房间列表
*/
@Operation(summary = "根据状态查询房间列表")
@SaCheckPermission("pms:room:query")
@GetMapping("/status")
public R<List<PmsRoomRoomVo>> listByStatus(
@Parameter(description = "部门ID") @RequestParam Long deptId,
@Parameter(description = "房间物理状态") @RequestParam(required = false) String roomStatus,
@Parameter(description = "清洁状态") @RequestParam(required = false) String cleaningStatus) {
return R.ok(pmsRoomRoomService.queryByStatus(deptId, roomStatus, cleaningStatus));
}
/**
* 更新房间状态
*/
@Operation(summary = "更新房间状态")
@SaCheckPermission("pms:room:updateStatus")
@Log(title = "房间状态更新", businessType = BusinessType.UPDATE)
@PutMapping("/{roomId}/status")
public R<Void> updateRoomStatus(
@PathVariable Long roomId,
@Parameter(description = "房间物理状态") @RequestParam String roomStatus,
@Parameter(description = "状态备注") @RequestParam(required = false) String statusRemarks) {
return toAjax(pmsRoomRoomService.updateRoomStatus(roomId, roomStatus, statusRemarks));
}
/**
* 更新清洁状态
*/
@Operation(summary = "更新清洁状态")
@SaCheckPermission("pms:room:updateStatus")
@Log(title = "房间清洁状态更新", businessType = BusinessType.UPDATE)
@PutMapping("/{roomId}/cleaning")
public R<Void> updateCleaningStatus(
@PathVariable Long roomId,
@Parameter(description = "清洁状态") @RequestParam String cleaningStatus) {
return toAjax(pmsRoomRoomService.updateCleaningStatus(roomId, cleaningStatus));
}
/**
* 批量更新房间状态
*/
@Operation(summary = "批量更新房间状态")
@SaCheckPermission("pms:room:updateStatus")
@Log(title = "批量房间状态更新", businessType = BusinessType.UPDATE)
@PutMapping("/batch/status")
public R<Void> batchUpdateRoomStatus(
@Parameter(description = "房间ID列表") @RequestBody List<Long> roomIds,
@Parameter(description = "房间物理状态") @RequestParam String roomStatus,
@Parameter(description = "状态备注") @RequestParam(required = false) String statusRemarks) {
return toAjax(pmsRoomRoomService.batchUpdateRoomStatus(roomIds, roomStatus, statusRemarks));
}
/**
* 批量更新清洁状态
*/
@Operation(summary = "批量更新清洁状态")
@SaCheckPermission("pms:room:updateStatus")
@Log(title = "批量房间清洁状态更新", businessType = BusinessType.UPDATE)
@PutMapping("/batch/cleaning")
public R<Void> batchUpdateCleaningStatus(
@Parameter(description = "房间ID列表") @RequestBody List<Long> roomIds,
@Parameter(description = "清洁状态") @RequestParam String cleaningStatus) {
return toAjax(pmsRoomRoomService.batchUpdateCleaningStatus(roomIds, cleaningStatus));
}
}

View File

@ -0,0 +1,162 @@
package org.dromara.pms.controller;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.pms.domain.vo.PmsRoomTypeVo;
import org.dromara.pms.domain.bo.PmsRoomTypeBo;
import org.dromara.pms.service.IPmsRoomTypeService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import org.dromara.common.log.enums.BusinessType;
/**
* 房型管理
*
* @author xuhf
* @date 2025-05-28
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/pms/roomType")
@Tag(name = "房型管理", description = "房型管理")
public class PmsRoomTypeController extends BaseController {
private final IPmsRoomTypeService pmsRoomTypeService;
/**
* 查询房型管理列表
*/
@Operation(summary = "查询房型管理列表")
@SaCheckPermission("pms:roomType:list")
@GetMapping("/list")
public TableDataInfo<PmsRoomTypeVo> list(PmsRoomTypeBo bo, PageQuery pageQuery) {
return pmsRoomTypeService.queryPageList(bo, pageQuery);
}
/**
* 导出房型管理列表
*/
@Operation(summary = "导出房型管理列表")
@SaCheckPermission("pms:roomType:export")
@Log(title = "房型管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmsRoomTypeBo bo, HttpServletResponse response) {
List<PmsRoomTypeVo> list = pmsRoomTypeService.queryList(bo);
ExcelUtil.exportExcel(list, "房型管理", PmsRoomTypeVo.class, response);
}
/**
* 获取房型管理详细信息
*/
@Operation(summary = "获取房型管理详细信息")
@Parameters({
@Parameter(name = "roomTypeId", description = "房型ID", in = ParameterIn.PATH, required = true)
})
@SaCheckPermission("pms:roomType:query")
@GetMapping("/{roomTypeId}")
public R<PmsRoomTypeVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long roomTypeId) {
return R.ok(pmsRoomTypeService.queryById(roomTypeId));
}
/**
* 新增房型管理
*/
@Operation(summary = "新增房型管理")
@SaCheckPermission("pms:roomType:add")
@Log(title = "房型管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmsRoomTypeBo bo) {
return toAjax(pmsRoomTypeService.insertByBo(bo));
}
/**
* 修改房型管理
*/
@Operation(summary = "修改房型管理")
@SaCheckPermission("pms:roomType:edit")
@Log(title = "房型管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmsRoomTypeBo bo) {
return toAjax(pmsRoomTypeService.updateByBo(bo));
}
/**
* 删除房型管理
*/
@Operation(summary = "删除房型管理")
@Parameters({
@Parameter(name = "roomTypeIds", description = "房型ID串", in = ParameterIn.PATH, required = true)
})
@SaCheckPermission("pms:roomType:remove")
@Log(title = "房型管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{roomTypeIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] roomTypeIds) {
return toAjax(pmsRoomTypeService.deleteWithValidByIds(List.of(roomTypeIds), true));
}
/**
* 根据部门ID查询房型列表
*/
@Operation(summary = "根据部门ID查询房型列表")
@Parameters({
@Parameter(name = "deptId", description = "部门ID", in = ParameterIn.PATH, required = true)
})
@SaCheckPermission("pms:roomType:list")
@GetMapping("/dept/{deptId}")
public R<List<PmsRoomTypeVo>> listByDeptId(@PathVariable Long deptId) {
return R.ok(pmsRoomTypeService.queryByDeptId(deptId));
}
/**
* 校验房型代码唯一性
*/
@Operation(summary = "校验房型代码唯一性")
@Parameters({
@Parameter(name = "typeCode", description = "房型代码", required = true),
@Parameter(name = "deptId", description = "部门ID", required = true),
@Parameter(name = "roomTypeId", description = "房型ID编辑时传入", required = false)
})
@SaCheckPermission("pms:roomType:list")
@GetMapping("/checkTypeCode")
public R<Boolean> checkTypeCode(@RequestParam String typeCode,
@RequestParam Long deptId,
@RequestParam(required = false) Long roomTypeId) {
return R.ok(pmsRoomTypeService.checkTypeCodeUnique(typeCode, deptId, roomTypeId));
}
/**
* 获取房型选项列表用于下拉选择
*/
@Operation(summary = "获取房型选项列表")
@Parameters({
@Parameter(name = "deptId", description = "部门ID可选", required = false)
})
@SaCheckPermission("pms:roomType:list")
@GetMapping("/options")
public R<List<Map<String, Object>>> getOptions(@RequestParam(required = false) Long deptId) {
return R.ok(pmsRoomTypeService.getOptions(deptId));
}
}

View File

@ -0,0 +1,231 @@
package org.dromara.pms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.pms.domain.PmsSpecialDatePricing;
import org.dromara.pms.domain.bo.PmsSpecialDatePricingBo;
import org.dromara.pms.domain.vo.PmsSpecialDatePricingVo;
import org.dromara.pms.service.IPmsSpecialDatePricingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
/**
* 特殊日期价格Controller
*
* @author PMS
* @date 2024-12-01
*/
@Validated
@RestController
@RequestMapping("/pms/pricing/special-dates")
public class PmsSpecialDatePricingController extends BaseController {
@Autowired
private IPmsSpecialDatePricingService pmsSpecialDatePricingService;
/**
* 查询特殊日期价格列表
*/
@SaCheckPermission("pms:pricing:specialDates:list")
@GetMapping("/list")
public TableDataInfo<PmsSpecialDatePricingVo> list(PmsSpecialDatePricingBo bo, PageQuery pageQuery) {
return pmsSpecialDatePricingService.queryPageList(bo, pageQuery);
}
/**
* 导出特殊日期价格列表
*/
@SaCheckPermission("pms:pricing:specialDates:export")
@Log(title = "特殊日期价格", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmsSpecialDatePricingBo bo, HttpServletResponse response) {
List<PmsSpecialDatePricingVo> list = pmsSpecialDatePricingService.exportList(bo);
ExcelUtil.exportExcel(list, "特殊日期价格", PmsSpecialDatePricingVo.class, response);
}
/**
* 获取特殊日期价格详细信息
*/
@SaCheckPermission("pms:pricing:specialDates:query")
@GetMapping("/{specialDateId}")
public R<PmsSpecialDatePricingVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long specialDateId) {
return R.ok(pmsSpecialDatePricingService.queryById(specialDateId));
}
/**
* 新增特殊日期价格
*/
@SaCheckPermission("pms:pricing:specialDates:add")
@Log(title = "特殊日期价格", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmsSpecialDatePricingBo bo) {
return toAjax(pmsSpecialDatePricingService.insertByBo(bo));
}
/**
* 修改特殊日期价格
*/
@SaCheckPermission("pms:pricing:specialDates:edit")
@Log(title = "特殊日期价格", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmsSpecialDatePricingBo bo) {
return toAjax(pmsSpecialDatePricingService.updateByBo(bo));
}
/**
* 删除特殊日期价格
*/
@SaCheckPermission("pms:pricing:specialDates:remove")
@Log(title = "特殊日期价格", businessType = BusinessType.DELETE)
@DeleteMapping("/{specialDateIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] specialDateIds) {
return toAjax(pmsSpecialDatePricingService.deleteWithValidByIds(List.of(specialDateIds), true));
}
/**
* 查询指定日期范围内的特殊日期价格
*/
@SaCheckPermission("pms:pricing:specialDates:query")
@GetMapping("/range")
public R<List<PmsSpecialDatePricing>> getSpecialDatesByRange(@RequestParam String tenantId,
@RequestParam Long deptId,
@RequestParam(required = false) Long roomTypeId,
@RequestParam LocalDate startDate,
@RequestParam LocalDate endDate) {
List<PmsSpecialDatePricing> specialDates = pmsSpecialDatePricingService.getSpecialDatesByRange(
tenantId, deptId, roomTypeId, startDate, endDate);
return R.ok(specialDates);
}
/**
* 查询指定日期的特殊价格
*/
@SaCheckPermission("pms:pricing:specialDates:query")
@GetMapping("/date")
public R<PmsSpecialDatePricing> getSpecialDateByDate(@RequestParam String tenantId,
@RequestParam Long deptId,
@RequestParam Long roomTypeId,
@RequestParam LocalDate specialDate) {
PmsSpecialDatePricing specialDatePricing = pmsSpecialDatePricingService.getSpecialDateByDate(
tenantId, deptId, roomTypeId, specialDate);
return R.ok(specialDatePricing);
}
/**
* 查询有效的特殊日期价格
*/
@SaCheckPermission("pms:pricing:specialDates:query")
@GetMapping("/active")
public R<List<PmsSpecialDatePricing>> getActiveSpecialDates(@RequestParam String tenantId,
@RequestParam Long deptId) {
List<PmsSpecialDatePricing> activeSpecialDates = pmsSpecialDatePricingService.getActiveSpecialDates(
tenantId, deptId);
return R.ok(activeSpecialDates);
}
/**
* 检查特殊日期冲突
*/
@SaCheckPermission("pms:pricing:specialDates:query")
@PostMapping("/check-conflict")
public R<Boolean> checkDateConflict(@RequestBody PmsSpecialDatePricingBo bo) {
return R.ok(pmsSpecialDatePricingService.checkDateConflict(bo));
}
/**
* 批量设置特殊日期价格
*/
@SaCheckPermission("pms:pricing:specialDates:add")
@Log(title = "批量设置特殊日期价格", businessType = BusinessType.INSERT)
@PostMapping("/batch")
public R<Void> batchInsertSpecialDates(@RequestBody List<PmsSpecialDatePricingBo> specialDates) {
return toAjax(pmsSpecialDatePricingService.batchInsertSpecialDates(specialDates));
}
/**
* 批量更新特殊日期价格状态
*/
@SaCheckPermission("pms:pricing:specialDates:edit")
@Log(title = "批量更新特殊日期价格状态", businessType = BusinessType.UPDATE)
@PutMapping("/batch/status")
public R<Void> batchUpdateStatus(@RequestBody Map<String, Object> params) {
List<Long> dateIds = (List<Long>) params.get("dateIds");
String status = (String) params.get("status");
return toAjax(pmsSpecialDatePricingService.batchUpdateStatus(dateIds, status));
}
/**
* 启用特殊日期价格
*/
@SaCheckPermission("pms:pricing:specialDates:edit")
@Log(title = "启用特殊日期价格", businessType = BusinessType.UPDATE)
@PutMapping("/{specialDateId}/enable")
public R<Void> enableSpecialDate(@NotNull(message = "特殊日期ID不能为空") @PathVariable Long specialDateId) {
return toAjax(pmsSpecialDatePricingService.enableSpecialDate(specialDateId));
}
/**
* 禁用特殊日期价格
*/
@SaCheckPermission("pms:pricing:specialDates:edit")
@Log(title = "禁用特殊日期价格", businessType = BusinessType.UPDATE)
@PutMapping("/{specialDateId}/disable")
public R<Void> disableSpecialDate(@NotNull(message = "特殊日期ID不能为空") @PathVariable Long specialDateId) {
return toAjax(pmsSpecialDatePricingService.disableSpecialDate(specialDateId));
}
/**
* 复制特殊日期价格到其他日期
*/
@SaCheckPermission("pms:pricing:specialDates:add")
@Log(title = "复制特殊日期价格", businessType = BusinessType.INSERT)
@PostMapping("/{sourceId}/copy")
public R<Void> copySpecialDate(@NotNull(message = "源特殊日期ID不能为空") @PathVariable Long sourceId,
@RequestParam LocalDate targetDate) {
return toAjax(pmsSpecialDatePricingService.copySpecialDate(sourceId, targetDate));
}
/**
* 查询按日期类型分组的统计信息
*/
@SaCheckPermission("pms:pricing:specialDates:query")
@GetMapping("/stats")
public R<List<Map<String, Object>>> getStatsByDateType(@RequestParam String tenantId,
@RequestParam Long deptId,
@RequestParam LocalDate startDate,
@RequestParam LocalDate endDate) {
List<Map<String, Object>> stats = pmsSpecialDatePricingService.getStatsByDateType(
tenantId, deptId, startDate, endDate);
return R.ok(stats);
}
/**
* 清理过期的特殊日期价格
*/
@SaCheckPermission("pms:pricing:specialDates:remove")
@Log(title = "清理过期特殊日期价格", businessType = BusinessType.DELETE)
@DeleteMapping("/clean-expired")
public R<Integer> cleanExpiredDates(@RequestParam LocalDate beforeDate) {
Integer count = pmsSpecialDatePricingService.cleanExpiredDates(beforeDate);
return R.ok(count);
}
}

View File

@ -0,0 +1,47 @@
package org.dromara.pms.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 联系人标签关联对象 pms_contact_tag_relations
*
* @author xuhf
* @date 2025-05-24
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_contact_tag_relations")
public class PmsContactTagRelations extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 关联唯一ID
*/
@TableId(value = "relation_id")
private Long relationId;
/**
* 联系人ID
*/
private Long contactId;
/**
* 标签ID
*/
private Long tagId;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
}

View File

@ -0,0 +1,72 @@
package org.dromara.pms.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 联系人标签对象 pms_contact_tags
*
* @author xuhf
* @date 2025-05-24
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_contact_tags")
public class PmsContactTags extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 标签唯一ID
*/
@TableId(value = "tag_id")
private Long tagId;
/**
* 部门ID (门店, 可空)
*/
private Long deptId;
/**
* 标签名称
*/
private String name;
/**
* 标签显示颜色
*/
private String color;
/**
* 标签分类
*/
private String category;
/**
* 标签描述
*/
private String description;
/**
* 是否为系统预设标签
*/
private Long isSystem;
/**
* 排序值
*/
private Long sortOrder;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
}

View File

@ -0,0 +1,150 @@
package org.dromara.pms.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 客户联系人对象 pms_customer_contacts
*
* @author xuhf
* @date 2025-05-24
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_customer_contacts")
public class PmsCustomerContacts extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 联系人唯一ID
*/
@TableId(value = "contact_id")
private Long contactId;
/**
* 联系人类型
*/
private String contactType;
/**
* 联系人姓名
*/
private String fullName;
/**
* 主要联系电话
*/
private String phoneNumber;
/**
* 电子邮件地址
*/
private String email;
/**
* 微信OpenID
*/
private String wechatOpenid;
/**
* 微信UnionID
*/
private String wechatUnionid;
/**
* 性别
*/
private String gender;
/**
* 出生日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private Date dateOfBirth;
/**
* 证件类型
*/
private String idType;
/**
* 证件号码 (加密存储)
*/
private String idNumberEncrypted;
/**
* 国籍代码
*/
private String nationalityCountryCode;
/**
* 地址-省份
*/
private String addressProvince;
/**
* 地址-城市
*/
private String addressCity;
/**
* 地址-区县
*/
private String addressDistrict;
/**
* 地址-详细地址
*/
private String addressDetail;
/**
* 邮政编码
*/
private String postalCode;
/**
* 联系人状态
*/
private String contactStatus;
/**
* 会员等级
*/
private String memberLevel;
/**
* 总入住次数
*/
private Long totalStays;
/**
* 总消费金额
*/
private Long totalAmount;
/**
* 最后入住日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private Date lastStayDate;
/**
* 备注信息
*/
private String remarks;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
}

View File

@ -0,0 +1,148 @@
package org.dromara.pms.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import jakarta.validation.constraints.*;
/**
* 小程序配置对象 pms_mp_settings
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_mp_settings")
public class PmsMpSetting extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 配置ID
*/
@TableId(value = "mp_setting_id", type = IdType.ASSIGN_ID)
private Long mpSettingId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 部门ID (门店)NULL表示租户级配置
*/
private Long deptId;
/**
* 小程序AppID
*/
@NotBlank(message = "小程序AppID不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 50, message = "小程序AppID长度不能超过50个字符")
private String appId;
/**
* 小程序名称
*/
@NotBlank(message = "小程序名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "小程序名称长度不能超过100个字符")
private String appName;
/**
* 小程序密钥
*/
@Size(max = 200, message = "小程序密钥长度不能超过200个字符")
private String appSecret;
/**
* 主题配置
*/
@Size(max = 2000, message = "主题配置长度不能超过2000个字符")
private String themeConfig;
/**
* 功能开关配置
*/
@Size(max = 2000, message = "功能开关配置长度不能超过2000个字符")
private String featureConfig;
/**
* 支付配置
*/
@Size(max = 2000, message = "支付配置长度不能超过2000个字符")
private String paymentConfig;
/**
* 通知配置
*/
@Size(max = 2000, message = "通知配置长度不能超过2000个字符")
private String notificationConfig;
/**
* 自定义配置
*/
@Size(max = 5000, message = "自定义配置长度不能超过5000个字符")
private String customConfig;
/**
* 版本号
*/
@Size(max = 20, message = "版本号长度不能超过20个字符")
private String version;
/**
* 是否启用
*/
@NotNull(message = "是否启用不能为空", groups = { AddGroup.class, EditGroup.class })
private Boolean isEnabled;
/**
* 排序值
*/
@NotNull(message = "排序值不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "排序值不能小于0")
private Integer sortOrder;
/**
* 状态
*/
@NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 备注
*/
@Size(max = 500, message = "备注长度不能超过500个字符")
private String remark;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
// 非数据库字段用于前端展示和查询
/**
* 门店名称
*/
@TableField(exist = false)
private String deptName;
/**
* 状态文本
*/
@TableField(exist = false)
private String statusText;
/**
* 是否继承配置
*/
@TableField(exist = false)
private Boolean isInherited;
}

View File

@ -0,0 +1,228 @@
package org.dromara.pms.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 价格计算历史对象 pms_pricing_calculations
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_pricing_calculations")
public class PmsPricingCalculation extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 计算记录ID
*/
@TableId(value = "calculation_id", type = IdType.AUTO)
private Long calculationId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 部门ID (门店)
*/
@NotNull(message = "部门ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deptId;
/**
* 房型ID
*/
@NotNull(message = "房型ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long roomTypeId;
/**
* 入住日期
*/
@NotNull(message = "入住日期不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate checkInDate;
/**
* 离店日期
*/
@NotNull(message = "离店日期不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate checkOutDate;
/**
* 成人数
*/
@NotNull(message = "成人数不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 1, message = "成人数不能小于1")
private Integer numAdults;
/**
* 儿童数
*/
@Min(value = 0, message = "儿童数不能小于0")
private Integer numChildren;
/**
* 渠道代码
*/
private String channelCode;
/**
* 会员等级
*/
private String memberLevel;
/**
* 提前预订天数
*/
@Min(value = 0, message = "提前预订天数不能小于0")
private Integer advanceBookingDays;
/**
* 基础价格
*/
@NotNull(message = "基础价格不能为空", groups = { AddGroup.class, EditGroup.class })
@DecimalMin(value = "0.00", message = "基础价格不能小于0")
@Digits(integer = 10, fraction = 2, message = "基础价格格式不正确")
private BigDecimal basePrice;
/**
* 最终价格
*/
@NotNull(message = "最终价格不能为空", groups = { AddGroup.class, EditGroup.class })
@DecimalMin(value = "0.00", message = "最终价格不能小于0")
@Digits(integer = 10, fraction = 2, message = "最终价格格式不正确")
private BigDecimal finalPrice;
/**
* 总折扣金额
*/
@DecimalMin(value = "0.00", message = "总折扣金额不能小于0")
@Digits(integer = 10, fraction = 2, message = "总折扣金额格式不正确")
private BigDecimal totalDiscount;
/**
* 应用的规则详情 (JSON)
*/
private String appliedRulesJson;
/**
* 计算上下文 (JSON)
*/
private String calculationContextJson;
/**
* 计算时间
*/
@NotNull(message = "计算时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDateTime calculationTime;
/**
* 计算来源
*/
private String calculationSource;
/**
* 关联订单ID
*/
private Long orderId;
/**
* 是否为最终预订
*/
private Boolean isFinalBooking;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
// 非数据库字段用于前端展示和查询
/**
* 房型名称
*/
@TableField(exist = false)
private String roomTypeName;
/**
* 渠道名称
*/
@TableField(exist = false)
private String channelName;
/**
* 订单号
*/
@TableField(exist = false)
private String orderNumber;
/**
* 入住天数
*/
@TableField(exist = false)
private Integer stayDays;
/**
* 折扣率
*/
@TableField(exist = false)
private BigDecimal discountRate;
/**
* 应用的规则列表 (解析JSON后的数据)
*/
@TableField(exist = false)
private List<Map<String, Object>> appliedRules;
/**
* 计算上下文 (解析JSON后的数据)
*/
@TableField(exist = false)
private Map<String, Object> calculationContext;
/**
* 计算来源文本
*/
@TableField(exist = false)
private String calculationSourceText;
/**
* 价格变化金额
*/
@TableField(exist = false)
private BigDecimal priceChange;
/**
* 价格变化率
*/
@TableField(exist = false)
private BigDecimal priceChangeRate;
/**
* 是否有折扣
*/
@TableField(exist = false)
private Boolean hasDiscount;
/**
* 规则数量
*/
@TableField(exist = false)
private Integer ruleCount;
}

View File

@ -0,0 +1,91 @@
package org.dromara.pms.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 房间锁定管理对象 pms_room_locks
*
* @author xuhf
* @date 2025-05-28
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_room_locks")
public class PmsRoomLock extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 锁定记录唯一ID
*/
@TableId(value = "lock_id")
private Long lockId;
/**
* 部门ID (门店)
*/
private Long deptId;
/**
* 房间ID
*/
private Long roomId;
/**
* 锁定类型
*/
private String lockType;
/**
* 锁定开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lockStartTime;
/**
* 锁定结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lockEndTime;
/**
* 锁定原因
*/
private String lockReason;
/**
* 锁定状态
*/
private String lockStatus;
/**
* 解锁时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date unlockTime;
/**
* 解锁操作人
*/
private Long unlockBy;
/**
* 解锁原因
*/
private String unlockReason;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
}

View File

@ -0,0 +1,246 @@
package org.dromara.pms.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
/**
* 房间价格规则对象 pms_room_pricing_rules
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_room_pricing_rules")
public class PmsRoomPricingRule extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 规则ID
*/
@TableId(value = "rule_id", type = IdType.AUTO)
private Long ruleId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 部门ID (门店)
*/
private Long deptId;
/**
* 规则名称
*/
@NotBlank(message = "规则名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "规则名称长度不能超过100个字符")
private String name;
/**
* 规则描述
*/
@Size(max = 500, message = "规则描述长度不能超过500个字符")
private String description;
/**
* 适用房型ID (NULL表示全部房型)
*/
private Long roomTypeId;
/**
* 适用日期范围开始
*/
private LocalDate dateRangeStart;
/**
* 适用日期范围结束
*/
private LocalDate dateRangeEnd;
/**
* 适用星期 (JSON数组)
*/
private String daysOfWeekJson;
/**
* 价格调整类型
*/
@NotBlank(message = "价格调整类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String priceAdjustmentType;
/**
* 调整值
*/
@NotNull(message = "调整值不能为空", groups = { AddGroup.class, EditGroup.class })
@DecimalMin(value = "0.00", message = "调整值不能小于0")
@Digits(integer = 8, fraction = 2, message = "调整值格式不正确")
private BigDecimal adjustmentValue;
/**
* 最小入住天数
*/
@Min(value = 1, message = "最小入住天数不能小于1")
private Integer minLengthOfStay;
/**
* 最大入住天数
*/
@Min(value = 1, message = "最大入住天数不能小于1")
private Integer maxLengthOfStay;
/**
* 最小提前预订天数
*/
@Min(value = 0, message = "最小提前预订天数不能小于0")
private Integer advanceBookingDaysMin;
/**
* 最大提前预订天数
*/
@Min(value = 0, message = "最大提前预订天数不能小于0")
private Integer advanceBookingDaysMax;
/**
* 渠道限制 (JSON数组)
*/
private String channelRestrictionsJson;
/**
* 最小客人数
*/
@Min(value = 1, message = "最小客人数不能小于1")
private Integer guestCountMin;
/**
* 最大客人数
*/
@Min(value = 1, message = "最大客人数不能小于1")
private Integer guestCountMax;
/**
* 会员等级限制 (JSON数组)
*/
private String memberLevelRestrictionsJson;
/**
* 优先级 (数字越大优先级越高)
*/
@NotNull(message = "优先级不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "优先级不能小于0")
private Integer priority;
/**
* 规则状态
*/
@NotBlank(message = "规则状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 规则生效开始日期
*/
private LocalDate effectiveStartDate;
/**
* 规则生效结束日期
*/
private LocalDate effectiveEndDate;
/**
* 最大折扣金额
*/
@DecimalMin(value = "0.00", message = "最大折扣金额不能小于0")
@Digits(integer = 8, fraction = 2, message = "最大折扣金额格式不正确")
private BigDecimal maxDiscountAmount;
/**
* 最低最终价格
*/
@DecimalMin(value = "0.00", message = "最低最终价格不能小于0")
@Digits(integer = 8, fraction = 2, message = "最低最终价格格式不正确")
private BigDecimal minFinalPrice;
/**
* 是否可与其他规则组合
*/
private Boolean isCombinable;
/**
* 使用次数限制
*/
@Min(value = 1, message = "使用次数限制不能小于1")
private Integer usageLimit;
/**
* 已使用次数
*/
private Integer usedCount;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
// 非数据库字段用于前端展示和查询
/**
* 房型名称
*/
@TableField(exist = false)
private String roomTypeName;
/**
* 适用星期列表 (解析JSON后的数据)
*/
@TableField(exist = false)
private List<Integer> daysOfWeek;
/**
* 渠道限制列表 (解析JSON后的数据)
*/
@TableField(exist = false)
private List<String> channelRestrictions;
/**
* 会员等级限制列表 (解析JSON后的数据)
*/
@TableField(exist = false)
private List<String> memberLevelRestrictions;
/**
* 规则状态文本
*/
@TableField(exist = false)
private String statusText;
/**
* 价格调整类型文本
*/
@TableField(exist = false)
private String priceAdjustmentTypeText;
/**
* 是否生效
*/
@TableField(exist = false)
private Boolean isEffective;
/**
* 剩余使用次数
*/
@TableField(exist = false)
private Integer remainingUsage;
}

View File

@ -0,0 +1,100 @@
package org.dromara.pms.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 房间管理对象 pms_room_rooms
*
* @author xuhf
* @date 2025-05-28
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_room_rooms")
public class PmsRoomRoom extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 房间唯一ID
*/
@TableId(value = "room_id")
private Long roomId;
/**
* 部门ID (门店)
*/
private Long deptId;
/**
* 房型ID
*/
private Long roomTypeId;
/**
* 房间号
*/
private String roomNumber;
/**
* 楼层
*/
private String floor;
/**
* 房间物理状态
*/
private String roomStatus;
/**
* 清洁状态
*/
private String cleaningStatus;
/**
* 房间描述
*/
private String description;
/**
* 房间特殊设施
*/
private String specialAmenities;
/**
* 最后清洁时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastCleaningTime;
/**
* 最后维护时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastMaintenanceTime;
/**
* 房间状态备注
*/
private String statusRemarks;
/**
* 排序值
*/
private Integer sortOrder;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
}

View File

@ -0,0 +1,103 @@
package org.dromara.pms.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 房型管理对象 pms_room_types
*
* @author xuhf
* @date 2025-05-28
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_room_types")
public class PmsRoomType extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 房型唯一ID
*/
@TableId(value = "room_type_id")
private Long roomTypeId;
/**
* 部门ID (门店)
*/
private Long deptId;
/**
* 房型名称
*/
private String typeName;
/**
* 房型代码
*/
private String typeCode;
/**
* 房型描述
*/
private String description;
/**
* 标准入住人数
*/
private Integer standardOccupancy;
/**
* 最大入住人数
*/
private Integer maxOccupancy;
/**
* 房间面积(平方米)
*/
private BigDecimal roomArea;
/**
* 床型配置
*/
private String bedConfiguration;
/**
* 房间设施
*/
private String amenities;
/**
* 默认价格
*/
private BigDecimal defaultPrice;
/**
* 房型状态
*/
private String status;
/**
* 排序值
*/
private Integer sortOrder;
/**
* 房型图片
*/
private String images;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
}

View File

@ -0,0 +1,179 @@
package org.dromara.pms.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 特殊日期价格对象 pms_special_date_pricing
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_special_date_pricing")
public class PmsSpecialDatePricing extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 特殊日期ID
*/
@TableId(value = "special_date_id", type = IdType.AUTO)
private Long specialDateId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 部门ID (门店)
*/
private Long deptId;
/**
* 房型ID (NULL表示全部房型)
*/
private Long roomTypeId;
/**
* 特殊日期
*/
@TableField("specific_date")
@NotNull(message = "特殊日期不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate specialDate;
/**
* 日期范围开始
*/
private LocalDate dateRangeStart;
/**
* 日期范围结束
*/
private LocalDate dateRangeEnd;
/**
* 日期类型
*/
@NotBlank(message = "日期类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String dateType;
/**
* 日期名称
*/
@TableField("name")
@NotBlank(message = "日期名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "日期名称长度不能超过100个字符")
private String dateName;
/**
* 价格调整类型
*/
@NotBlank(message = "价格调整类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String priceAdjustmentType;
/**
* 调整值
*/
@NotNull(message = "调整值不能为空", groups = { AddGroup.class, EditGroup.class })
@DecimalMin(value = "0.00", message = "调整值不能小于0")
@Digits(integer = 8, fraction = 2, message = "调整值格式不正确")
private BigDecimal adjustmentValue;
/**
* 固定价格
*/
@DecimalMin(value = "0.00", message = "固定价格不能小于0")
@Digits(integer = 8, fraction = 2, message = "固定价格格式不正确")
private BigDecimal fixedPrice;
/**
* 优先级
*/
@NotNull(message = "优先级不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "优先级不能小于0")
private Integer priority;
/**
* 状态
*/
@NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 描述
*/
@Size(max = 500, message = "描述长度不能超过500个字符")
private String description;
/**
* 是否每年重复
*/
private Boolean isRecurringYearly;
/**
* 最小入住天数
*/
@Min(value = 1, message = "最小入住天数不能小于1")
private Integer minLengthOfStay;
/**
* 最大入住天数
*/
@Min(value = 1, message = "最大入住天数不能小于1")
private Integer maxLengthOfStay;
/**
* 渠道限制 (JSON数组)
*/
private String channelRestrictionsJson;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
// 非数据库字段用于前端展示和查询
/**
* 房型名称
*/
@TableField(exist = false)
private String roomTypeName;
/**
* 日期类型文本
*/
@TableField(exist = false)
private String dateTypeText;
/**
* 价格调整类型文本
*/
@TableField(exist = false)
private String priceAdjustmentTypeText;
/**
* 状态文本
*/
@TableField(exist = false)
private String statusText;
/**
* 是否生效
*/
@TableField(exist = false)
private Boolean isEffective;
}

View File

@ -0,0 +1,149 @@
package org.dromara.pms.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import jakarta.validation.constraints.*;
/**
* 租户配置对象 pms_tenant_settings
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_tenant_settings")
public class PmsTenantSetting extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 配置ID
*/
@TableId(value = "setting_id", type = IdType.ASSIGN_ID)
private Long settingId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 部门ID (门店)NULL表示租户级配置
*/
private Long deptId;
/**
* 配置分组
*/
@NotBlank(message = "配置分组不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 50, message = "配置分组长度不能超过50个字符")
private String settingGroup;
/**
* 配置键
*/
@NotBlank(message = "配置键不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "配置键长度不能超过100个字符")
private String settingKey;
/**
* 配置值
*/
@Size(max = 2000, message = "配置值长度不能超过2000个字符")
private String settingValue;
/**
* 配置名称
*/
@NotBlank(message = "配置名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "配置名称长度不能超过100个字符")
private String settingName;
/**
* 配置描述
*/
@Size(max = 500, message = "配置描述长度不能超过500个字符")
private String settingDescription;
/**
* 配置类型
*/
@NotBlank(message = "配置类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String settingType;
/**
* 是否敏感配置
*/
@NotNull(message = "是否敏感配置不能为空", groups = { AddGroup.class, EditGroup.class })
private Boolean isSensitive;
/**
* 是否可编辑
*/
@NotNull(message = "是否可编辑不能为空", groups = { AddGroup.class, EditGroup.class })
private Boolean isEditable;
/**
* 是否系统配置
*/
@NotNull(message = "是否系统配置不能为空", groups = { AddGroup.class, EditGroup.class })
private Boolean isSystem;
/**
* 排序值
*/
@NotNull(message = "排序值不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "排序值不能小于0")
private Integer sortOrder;
/**
* 状态
*/
@NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
// 非数据库字段用于前端展示和查询
/**
* 门店名称
*/
@TableField(exist = false)
private String deptName;
/**
* 配置类型文本
*/
@TableField(exist = false)
private String settingTypeText;
/**
* 状态文本
*/
@TableField(exist = false)
private String statusText;
/**
* 是否继承配置
*/
@TableField(exist = false)
private Boolean isInherited;
/**
* 父级配置值
*/
@TableField(exist = false)
private String parentValue;
}

View File

@ -0,0 +1,182 @@
package org.dromara.pms.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import jakarta.validation.constraints.*;
import java.time.LocalDateTime;
/**
* 用户设备对象 pms_tenant_user_devices
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pms_tenant_user_devices")
public class PmsTenantUserDevice extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 设备ID
*/
@TableId(value = "device_id", type = IdType.ASSIGN_ID)
private Long deviceId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 用户ID
*/
@NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long userId;
/**
* 设备唯一标识
*/
@NotBlank(message = "设备唯一标识不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "设备唯一标识长度不能超过100个字符")
private String deviceUuid;
/**
* 设备名称
*/
@Size(max = 100, message = "设备名称长度不能超过100个字符")
private String deviceName;
/**
* 设备类型
*/
@NotBlank(message = "设备类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String deviceType;
/**
* 设备型号
*/
@Size(max = 100, message = "设备型号长度不能超过100个字符")
private String deviceModel;
/**
* 操作系统
*/
@Size(max = 50, message = "操作系统长度不能超过50个字符")
private String osName;
/**
* 操作系统版本
*/
@Size(max = 50, message = "操作系统版本长度不能超过50个字符")
private String osVersion;
/**
* 应用版本
*/
@Size(max = 20, message = "应用版本长度不能超过20个字符")
private String appVersion;
/**
* 推送令牌
*/
@Size(max = 200, message = "推送令牌长度不能超过200个字符")
private String pushToken;
/**
* 设备状态
*/
@NotBlank(message = "设备状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String deviceStatus;
/**
* 是否在线
*/
@NotNull(message = "是否在线不能为空", groups = { AddGroup.class, EditGroup.class })
private Boolean isOnline;
/**
* 最后活跃时间
*/
private LocalDateTime lastActiveTime;
/**
* 注册时间
*/
private LocalDateTime registerTime;
/**
* 登录次数
*/
@NotNull(message = "登录次数不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "登录次数不能小于0")
private Integer loginCount;
/**
* 最后登录时间
*/
private LocalDateTime lastLoginTime;
/**
* 最后登录IP
*/
@Size(max = 50, message = "最后登录IP长度不能超过50个字符")
private String lastLoginIp;
/**
* 设备信息
*/
@Size(max = 1000, message = "设备信息长度不能超过1000个字符")
private String deviceInfo;
/**
* 备注
*/
@Size(max = 500, message = "备注长度不能超过500个字符")
private String remark;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
// 非数据库字段用于前端展示和查询
/**
* 用户名
*/
@TableField(exist = false)
private String userName;
/**
* 用户昵称
*/
@TableField(exist = false)
private String nickName;
/**
* 设备类型文本
*/
@TableField(exist = false)
private String deviceTypeText;
/**
* 设备状态文本
*/
@TableField(exist = false)
private String deviceStatusText;
/**
* 在线状态文本
*/
@TableField(exist = false)
private String onlineStatusText;
}

View File

@ -0,0 +1,42 @@
package org.dromara.pms.domain.bo;
import org.dromara.pms.domain.PmsContactTagRelations;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 联系人标签关联业务对象 pms_contact_tag_relations
*
* @author xuhf
* @date 2025-05-24
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsContactTagRelations.class, reverseConvertGenerate = false)
public class PmsContactTagRelationsBo extends BaseEntity {
/**
* 关联唯一ID
*/
@NotNull(message = "关联唯一ID不能为空", groups = { EditGroup.class })
private Long relationId;
/**
* 联系人ID
*/
@NotNull(message = "联系人ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long contactId;
/**
* 标签ID
*/
@NotNull(message = "标签ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long tagId;
}

View File

@ -0,0 +1,72 @@
package org.dromara.pms.domain.bo;
import org.dromara.pms.domain.PmsContactTags;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 联系人标签业务对象 pms_contact_tags
*
* @author xuhf
* @date 2025-05-24
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsContactTags.class, reverseConvertGenerate = false)
public class PmsContactTagsBo extends BaseEntity {
/**
* 标签唯一ID
*/
@NotNull(message = "标签唯一ID不能为空", groups = { EditGroup.class })
private Long tagId;
/**
* 部门ID (门店, 可空)
*/
private Long deptId;
/**
* 标签名称
*/
@NotBlank(message = "标签名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(min = 1, max = 50, message = "标签名称长度应在1-50个字符之间", groups = { AddGroup.class, EditGroup.class })
private String name;
/**
* 标签显示颜色
*/
@NotBlank(message = "标签颜色不能为空", groups = { AddGroup.class, EditGroup.class })
@Pattern(regexp = "^#[0-9A-Fa-f]{6}$", message = "标签颜色格式不正确", groups = { AddGroup.class, EditGroup.class })
private String color;
/**
* 标签分类
*/
@NotBlank(message = "标签分类不能为空", groups = { AddGroup.class, EditGroup.class })
private String category;
/**
* 标签描述
*/
@Size(max = 200, message = "标签描述不能超过200个字符", groups = { AddGroup.class, EditGroup.class })
private String description;
/**
* 是否为系统预设标签
*/
private Long isSystem;
/**
* 排序值
*/
@Min(value = 0, message = "排序值不能小于0", groups = { AddGroup.class, EditGroup.class })
@Max(value = 9999, message = "排序值不能大于9999", groups = { AddGroup.class, EditGroup.class })
private Long sortOrder;
}

View File

@ -0,0 +1,161 @@
package org.dromara.pms.domain.bo;
import org.dromara.pms.domain.PmsCustomerContacts;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 客户联系人业务对象 pms_customer_contacts
*
* @author xuhf
* @date 2025-05-24
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsCustomerContacts.class, reverseConvertGenerate = false)
public class PmsCustomerContactsBo extends BaseEntity {
/**
* 联系人唯一ID
*/
@NotNull(message = "联系人唯一ID不能为空", groups = { EditGroup.class })
private Long contactId;
/**
* 联系人类型
*/
@NotBlank(message = "联系人类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String contactType;
/**
* 联系人姓名
*/
@NotBlank(message = "联系人姓名不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 255, message = "联系人姓名长度不能超过255个字符")
private String fullName;
/**
* 主要联系电话
*/
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
@Size(max = 50, message = "电话号码长度不能超过50个字符")
private String phoneNumber;
/**
* 电子邮件地址
*/
@Email(message = "邮箱格式不正确")
@Size(max = 255, message = "邮箱地址长度不能超过255个字符")
private String email;
/**
* 微信OpenID
*/
@Size(max = 100, message = "微信OpenID长度不能超过100个字符")
private String wechatOpenid;
/**
* 微信UnionID
*/
@Size(max = 100, message = "微信UnionID长度不能超过100个字符")
private String wechatUnionid;
/**
* 性别
*/
private String gender;
/**
* 出生日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private Date dateOfBirth;
/**
* 证件类型
*/
private String idType;
/**
* 证件号码 (加密存储)
*/
private String idNumberEncrypted;
/**
* 国籍代码
*/
@Size(max = 10, message = "国籍代码长度不能超过10个字符")
private String nationalityCountryCode;
/**
* 地址-省份
*/
@Size(max = 100, message = "省份名称长度不能超过100个字符")
private String addressProvince;
/**
* 地址-城市
*/
@Size(max = 100, message = "城市名称长度不能超过100个字符")
private String addressCity;
/**
* 地址-区县
*/
@Size(max = 100, message = "区县名称长度不能超过100个字符")
private String addressDistrict;
/**
* 地址-详细地址
*/
@Size(max = 500, message = "详细地址长度不能超过500个字符")
private String addressDetail;
/**
* 邮政编码
*/
@Pattern(regexp = "^\\d{6}$", message = "邮政编码格式不正确")
private String postalCode;
/**
* 联系人状态
*/
private String contactStatus;
/**
* 会员等级
*/
private String memberLevel;
/**
* 总入住次数
*/
@Min(value = 0, message = "总入住次数不能为负数")
private Integer totalStays;
/**
* 总消费金额
*/
@DecimalMin(value = "0.00", message = "总消费金额不能为负数")
private java.math.BigDecimal totalAmount;
/**
* 最后入住日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private Date lastStayDate;
/**
* 备注信息
*/
@Size(max = 1000, message = "备注信息长度不能超过1000个字符")
private String remarks;
}

View File

@ -0,0 +1,146 @@
package org.dromara.pms.domain.bo;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.pms.domain.PmsPricingCalculation;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 价格计算历史业务对象 pms_pricing_calculations
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsPricingCalculation.class, reverseConvertGenerate = false)
public class PmsPricingCalculationBo extends BaseEntity {
/**
* 计算记录ID
*/
private Long calculationId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 部门ID (门店)
*/
@NotNull(message = "部门ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deptId;
/**
* 房型ID
*/
@NotNull(message = "房型ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long roomTypeId;
/**
* 入住日期
*/
@NotNull(message = "入住日期不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate checkInDate;
/**
* 离店日期
*/
@NotNull(message = "离店日期不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate checkOutDate;
/**
* 成人数
*/
@NotNull(message = "成人数不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 1, message = "成人数不能小于1")
private Integer numAdults;
/**
* 儿童数
*/
@Min(value = 0, message = "儿童数不能小于0")
private Integer numChildren;
/**
* 渠道代码
*/
private String channelCode;
/**
* 会员等级
*/
private String memberLevel;
/**
* 提前预订天数
*/
@Min(value = 0, message = "提前预订天数不能小于0")
private Integer advanceBookingDays;
/**
* 基础价格
*/
@NotNull(message = "基础价格不能为空", groups = { AddGroup.class, EditGroup.class })
@DecimalMin(value = "0.00", message = "基础价格不能小于0")
@Digits(integer = 10, fraction = 2, message = "基础价格格式不正确")
private BigDecimal basePrice;
/**
* 最终价格
*/
@NotNull(message = "最终价格不能为空", groups = { AddGroup.class, EditGroup.class })
@DecimalMin(value = "0.00", message = "最终价格不能小于0")
@Digits(integer = 10, fraction = 2, message = "最终价格格式不正确")
private BigDecimal finalPrice;
/**
* 总折扣金额
*/
@DecimalMin(value = "0.00", message = "总折扣金额不能小于0")
@Digits(integer = 10, fraction = 2, message = "总折扣金额格式不正确")
private BigDecimal totalDiscount;
/**
* 应用的规则列表
*/
private List<Map<String, Object>> appliedRules;
/**
* 计算上下文
*/
private Map<String, Object> calculationContext;
/**
* 计算时间
*/
@NotNull(message = "计算时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDateTime calculationTime;
/**
* 计算来源
*/
private String calculationSource;
/**
* 关联订单ID
*/
private Long orderId;
/**
* 是否为最终预订
*/
private Boolean isFinalBooking;
}

View File

@ -0,0 +1,92 @@
package org.dromara.pms.domain.bo;
import org.dromara.pms.domain.PmsRoomLock;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 房间锁定管理业务对象 pms_room_locks
*
* @author xuhf
* @date 2025-05-28
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsRoomLock.class, reverseConvertGenerate = false)
public class PmsRoomLockBo extends BaseEntity {
/**
* 锁定记录唯一ID
*/
@NotNull(message = "锁定记录唯一ID不能为空", groups = { EditGroup.class })
private Long lockId;
/**
* 部门ID (门店)
*/
@NotNull(message = "部门ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deptId;
/**
* 房间ID
*/
@NotNull(message = "房间ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long roomId;
/**
* 锁定类型
*/
@NotBlank(message = "锁定类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String lockType;
/**
* 锁定开始时间
*/
@NotNull(message = "锁定开始时间不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lockStartTime;
/**
* 锁定结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lockEndTime;
/**
* 锁定原因
*/
@NotBlank(message = "锁定原因不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 500, message = "锁定原因长度不能超过500个字符")
private String lockReason;
/**
* 锁定状态
*/
@NotBlank(message = "锁定状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String lockStatus;
/**
* 解锁时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date unlockTime;
/**
* 解锁操作人
*/
private Long unlockBy;
/**
* 解锁原因
*/
@Size(max = 500, message = "解锁原因长度不能超过500个字符")
private String unlockReason;
}

View File

@ -0,0 +1,188 @@
package org.dromara.pms.domain.bo;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.pms.domain.PmsRoomPricingRule;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
/**
* 房间价格规则业务对象 pms_room_pricing_rules
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsRoomPricingRule.class, reverseConvertGenerate = false)
public class PmsRoomPricingRuleBo extends BaseEntity {
/**
* 规则ID
*/
private Long ruleId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 部门ID (门店)
*/
private Long deptId;
/**
* 规则名称
*/
@NotBlank(message = "规则名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "规则名称长度不能超过100个字符")
private String name;
/**
* 规则描述
*/
@Size(max = 500, message = "规则描述长度不能超过500个字符")
private String description;
/**
* 适用房型ID (NULL表示全部房型)
*/
private Long roomTypeId;
/**
* 适用日期范围开始
*/
private LocalDate dateRangeStart;
/**
* 适用日期范围结束
*/
private LocalDate dateRangeEnd;
/**
* 适用星期列表
*/
private List<Integer> daysOfWeek;
/**
* 价格调整类型
*/
@NotBlank(message = "价格调整类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String priceAdjustmentType;
/**
* 调整值
*/
@NotNull(message = "调整值不能为空", groups = { AddGroup.class, EditGroup.class })
@DecimalMin(value = "0.00", message = "调整值不能小于0")
@Digits(integer = 8, fraction = 2, message = "调整值格式不正确")
private BigDecimal adjustmentValue;
/**
* 最小入住天数
*/
@Min(value = 1, message = "最小入住天数不能小于1")
private Integer minLengthOfStay;
/**
* 最大入住天数
*/
@Min(value = 1, message = "最大入住天数不能小于1")
private Integer maxLengthOfStay;
/**
* 最小提前预订天数
*/
@Min(value = 0, message = "最小提前预订天数不能小于0")
private Integer advanceBookingDaysMin;
/**
* 最大提前预订天数
*/
@Min(value = 0, message = "最大提前预订天数不能小于0")
private Integer advanceBookingDaysMax;
/**
* 渠道限制列表
*/
private List<String> channelRestrictions;
/**
* 最小客人数
*/
@Min(value = 1, message = "最小客人数不能小于1")
private Integer guestCountMin;
/**
* 最大客人数
*/
@Min(value = 1, message = "最大客人数不能小于1")
private Integer guestCountMax;
/**
* 会员等级限制列表
*/
private List<String> memberLevelRestrictions;
/**
* 优先级 (数字越大优先级越高)
*/
@NotNull(message = "优先级不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "优先级不能小于0")
private Integer priority;
/**
* 规则状态
*/
@NotBlank(message = "规则状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 规则生效开始日期
*/
private LocalDate effectiveStartDate;
/**
* 规则生效结束日期
*/
private LocalDate effectiveEndDate;
/**
* 最大折扣金额
*/
@DecimalMin(value = "0.00", message = "最大折扣金额不能小于0")
@Digits(integer = 8, fraction = 2, message = "最大折扣金额格式不正确")
private BigDecimal maxDiscountAmount;
/**
* 最低最终价格
*/
@DecimalMin(value = "0.00", message = "最低最终价格不能小于0")
@Digits(integer = 8, fraction = 2, message = "最低最终价格格式不正确")
private BigDecimal minFinalPrice;
/**
* 是否可与其他规则组合
*/
private Boolean isCombinable;
/**
* 使用次数限制
*/
@Min(value = 1, message = "使用次数限制不能小于1")
private Integer usageLimit;
/**
* 已使用次数
*/
private Integer usedCount;
}

View File

@ -0,0 +1,103 @@
package org.dromara.pms.domain.bo;
import org.dromara.pms.domain.PmsRoomRoom;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 房间管理业务对象 pms_room_rooms
*
* @author xuhf
* @date 2025-05-28
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsRoomRoom.class, reverseConvertGenerate = false)
public class PmsRoomRoomBo extends BaseEntity {
/**
* 房间唯一ID
*/
@NotNull(message = "房间唯一ID不能为空", groups = { EditGroup.class })
private Long roomId;
/**
* 部门ID (门店)
*/
@NotNull(message = "部门ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deptId;
/**
* 房型ID
*/
@NotNull(message = "房型ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long roomTypeId;
/**
* 房间号
*/
@NotBlank(message = "房间号不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 50, message = "房间号长度不能超过50个字符")
private String roomNumber;
/**
* 楼层
*/
@Size(max = 20, message = "楼层长度不能超过20个字符")
private String floor;
/**
* 房间物理状态
*/
@NotBlank(message = "房间物理状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String roomStatus;
/**
* 清洁状态
*/
@NotBlank(message = "清洁状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String cleaningStatus;
/**
* 房间描述
*/
@Size(max = 500, message = "房间描述长度不能超过500个字符")
private String description;
/**
* 房间特殊设施
*/
@Size(max = 1000, message = "房间特殊设施长度不能超过1000个字符")
private String specialAmenities;
/**
* 最后清洁时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastCleaningTime;
/**
* 最后维护时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastMaintenanceTime;
/**
* 房间状态备注
*/
@Size(max = 500, message = "房间状态备注长度不能超过500个字符")
private String statusRemarks;
/**
* 排序值
*/
private Integer sortOrder;
}

View File

@ -0,0 +1,116 @@
package org.dromara.pms.domain.bo;
import org.dromara.pms.domain.PmsRoomType;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
/**
* 房型管理业务对象 pms_room_types
*
* @author xuhf
* @date 2025-05-28
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsRoomType.class, reverseConvertGenerate = false)
public class PmsRoomTypeBo extends BaseEntity {
/**
* 房型唯一ID
*/
@NotNull(message = "房型唯一ID不能为空", groups = { EditGroup.class })
private Long roomTypeId;
/**
* 部门ID (门店)
*/
private Long deptId;
/**
* 房型名称
*/
@NotBlank(message = "房型名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "房型名称长度不能超过100个字符")
private String typeName;
/**
* 房型代码
*/
@NotBlank(message = "房型代码不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 50, message = "房型代码长度不能超过50个字符")
private String typeCode;
/**
* 房型描述
*/
@Size(max = 500, message = "房型描述长度不能超过500个字符")
private String description;
/**
* 标准入住人数
*/
@NotNull(message = "标准入住人数不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 1, message = "标准入住人数不能小于1")
@Max(value = 20, message = "标准入住人数不能大于20")
private Integer standardOccupancy;
/**
* 最大入住人数
*/
@NotNull(message = "最大入住人数不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 1, message = "最大入住人数不能小于1")
@Max(value = 20, message = "最大入住人数不能大于20")
private Integer maxOccupancy;
/**
* 房间面积(平方米)
*/
@DecimalMin(value = "0.01", message = "房间面积必须大于0")
@DecimalMax(value = "9999.99", message = "房间面积不能超过9999.99平方米")
private BigDecimal roomArea;
/**
* 床型配置
*/
@Size(max = 200, message = "床型配置长度不能超过200个字符")
private String bedConfiguration;
/**
* 房间设施
*/
@Size(max = 1000, message = "房间设施长度不能超过1000个字符")
private String amenities;
/**
* 默认价格
*/
@NotNull(message = "默认价格不能为空", groups = { AddGroup.class, EditGroup.class })
@DecimalMin(value = "0.01", message = "默认价格必须大于0")
@DecimalMax(value = "99999.99", message = "默认价格不能超过99999.99")
private BigDecimal defaultPrice;
/**
* 房型状态
*/
@NotBlank(message = "房型状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 排序值
*/
@Min(value = 0, message = "排序值不能为负数")
private Integer sortOrder;
/**
* 房型图片
*/
@Size(max = 2000, message = "房型图片URL长度不能超过2000个字符")
private String images;
}

View File

@ -0,0 +1,98 @@
package org.dromara.pms.domain.bo;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.pms.domain.PmsSpecialDatePricing;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 特殊日期价格业务对象 pms_special_date_pricing
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsSpecialDatePricing.class, reverseConvertGenerate = false)
public class PmsSpecialDatePricingBo extends BaseEntity {
/**
* 特殊日期ID
*/
private Long specialDateId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 部门ID (门店)
*/
private Long deptId;
/**
* 房型ID (NULL表示全部房型)
*/
private Long roomTypeId;
/**
* 特殊日期
*/
@NotNull(message = "特殊日期不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate specialDate;
/**
* 日期类型
*/
@NotBlank(message = "日期类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String dateType;
/**
* 日期名称
*/
@NotBlank(message = "日期名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "日期名称长度不能超过100个字符")
private String dateName;
/**
* 价格调整类型
*/
@NotBlank(message = "价格调整类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String priceAdjustmentType;
/**
* 调整值
*/
@NotNull(message = "调整值不能为空", groups = { AddGroup.class, EditGroup.class })
@DecimalMin(value = "0.00", message = "调整值不能小于0")
@Digits(integer = 8, fraction = 2, message = "调整值格式不正确")
private BigDecimal adjustmentValue;
/**
* 优先级
*/
@NotNull(message = "优先级不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "优先级不能小于0")
private Integer priority;
/**
* 状态
*/
@NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 描述
*/
@Size(max = 500, message = "描述长度不能超过500个字符")
private String description;
}

View File

@ -0,0 +1,108 @@
package org.dromara.pms.domain.bo;
import org.dromara.pms.domain.PmsTenantSetting;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 租户配置业务对象 pms_tenant_settings
*
* @author PMS
* @date 2024-12-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmsTenantSetting.class, reverseConvertGenerate = false)
public class PmsTenantSettingBo extends BaseEntity {
/**
* 配置ID
*/
private Long settingId;
/**
* 租户ID
*/
@NotBlank(message = "租户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId;
/**
* 部门ID (门店)NULL表示租户级配置
*/
private Long deptId;
/**
* 配置分组
*/
@NotBlank(message = "配置分组不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 50, message = "配置分组长度不能超过50个字符")
private String settingGroup;
/**
* 配置键
*/
@NotBlank(message = "配置键不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "配置键长度不能超过100个字符")
private String settingKey;
/**
* 配置值
*/
@Size(max = 2000, message = "配置值长度不能超过2000个字符")
private String settingValue;
/**
* 配置名称
*/
@NotBlank(message = "配置名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "配置名称长度不能超过100个字符")
private String settingName;
/**
* 配置描述
*/
@Size(max = 500, message = "配置描述长度不能超过500个字符")
private String settingDescription;
/**
* 配置类型
*/
@NotBlank(message = "配置类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String settingType;
/**
* 是否敏感配置
*/
@NotNull(message = "是否敏感配置不能为空", groups = { AddGroup.class, EditGroup.class })
private Boolean isSensitive;
/**
* 是否可编辑
*/
@NotNull(message = "是否可编辑不能为空", groups = { AddGroup.class, EditGroup.class })
private Boolean isEditable;
/**
* 是否系统配置
*/
@NotNull(message = "是否系统配置不能为空", groups = { AddGroup.class, EditGroup.class })
private Boolean isSystem;
/**
* 排序值
*/
@NotNull(message = "排序值不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "排序值不能小于0")
private Integer sortOrder;
/**
* 状态
*/
@NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
}

View File

@ -0,0 +1,70 @@
package org.dromara.pms.domain.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 价格调整类型枚举
*
* @author ruoyi
* @date 2024-12-19
*/
@Getter
@AllArgsConstructor
public enum PriceAdjustmentType {
/**
* 固定金额调整
*/
FIXED_AMOUNT("fixed_amount", "固定金额"),
/**
* 百分比调整
*/
PERCENTAGE("percentage", "百分比"),
/**
* 固定价格
*/
FIXED_PRICE("fixed_price", "固定价格");
/**
* 数据库存储值
*/
private final String code;
/**
* 显示名称
*/
private final String description;
/**
* 根据代码获取枚举
*
* @param code 代码
* @return 枚举值
*/
public static PriceAdjustmentType fromCode(String code) {
for (PriceAdjustmentType type : values()) {
if (type.getCode().equals(code)) {
return type;
}
}
throw new IllegalArgumentException("未知的价格调整类型: " + code);
}
/**
* 检查代码是否有效
*
* @param code 代码
* @return 是否有效
*/
public static boolean isValidCode(String code) {
for (PriceAdjustmentType type : values()) {
if (type.getCode().equals(code)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,98 @@
package org.dromara.pms.domain.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 价格规则状态枚举
*
* @author ruoyi
* @date 2024-12-19
*/
@Getter
@AllArgsConstructor
public enum PricingRuleStatus {
/**
* 草稿状态
*/
DRAFT("draft", "草稿"),
/**
* 启用状态
*/
ACTIVE("active", "启用"),
/**
* 禁用状态
*/
INACTIVE("inactive", "禁用"),
/**
* 已过期
*/
EXPIRED("expired", "已过期"),
/**
* 已删除
*/
DELETED("deleted", "已删除");
/**
* 数据库存储值
*/
private final String code;
/**
* 显示名称
*/
private final String description;
/**
* 根据代码获取枚举
*
* @param code 代码
* @return 枚举值
*/
public static PricingRuleStatus fromCode(String code) {
for (PricingRuleStatus status : values()) {
if (status.getCode().equals(code)) {
return status;
}
}
throw new IllegalArgumentException("未知的价格规则状态: " + code);
}
/**
* 检查代码是否有效
*
* @param code 代码
* @return 是否有效
*/
public static boolean isValidCode(String code) {
for (PricingRuleStatus status : values()) {
if (status.getCode().equals(code)) {
return true;
}
}
return false;
}
/**
* 检查是否为活跃状态
*
* @return 是否活跃
*/
public boolean isActive() {
return this == ACTIVE;
}
/**
* 检查是否可以编辑
*
* @return 是否可编辑
*/
public boolean isEditable() {
return this == DRAFT || this == INACTIVE;
}
}

View File

@ -0,0 +1,142 @@
package org.dromara.pms.domain.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 配置类型枚举
*
* @author PMS
* @date 2024-12-01
*/
@Getter
@AllArgsConstructor
public enum SettingType {
/**
* 字符串类型
*/
STRING("string", "字符串"),
/**
* 数字类型
*/
NUMBER("number", "数字"),
/**
* 布尔类型
*/
BOOLEAN("boolean", "布尔值"),
/**
* JSON类型
*/
JSON("json", "JSON对象"),
/**
* 数组类型
*/
ARRAY("array", "数组"),
/**
* 日期类型
*/
DATE("date", "日期"),
/**
* 时间类型
*/
DATETIME("datetime", "日期时间"),
/**
* 文件路径类型
*/
FILE_PATH("file_path", "文件路径"),
/**
* URL类型
*/
URL("url", "URL地址"),
/**
* 邮箱类型
*/
EMAIL("email", "邮箱地址"),
/**
* 电话类型
*/
PHONE("phone", "电话号码"),
/**
* 密码类型
*/
PASSWORD("password", "密码"),
/**
* 颜色类型
*/
COLOR("color", "颜色值"),
/**
* 枚举类型
*/
ENUM("enum", "枚举值");
/**
* 类型代码
*/
private final String code;
/**
* 类型描述
*/
private final String description;
/**
* 根据代码获取枚举
*/
public static SettingType getByCode(String code) {
for (SettingType type : values()) {
if (type.getCode().equals(code)) {
return type;
}
}
return STRING; // 默认返回字符串类型
}
/**
* 验证配置值格式是否正确
*/
public boolean validateValue(String value) {
if (value == null || value.trim().isEmpty()) {
return true; // 空值由业务层校验
}
try {
switch (this) {
case NUMBER:
Double.parseDouble(value);
return true;
case BOOLEAN:
return "true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value);
case JSON:
// 简单的JSON格式检查
return value.trim().startsWith("{") && value.trim().endsWith("}") ||
value.trim().startsWith("[") && value.trim().endsWith("]");
case EMAIL:
return value.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
case PHONE:
return value.matches("^1[3-9]\\d{9}$");
case URL:
return value.matches("^https?://.*");
case COLOR:
return value.matches("^#[0-9A-Fa-f]{6}$");
default:
return true; // 其他类型暂不校验
}
} catch (Exception e) {
return false;
}
}
}

View File

@ -0,0 +1,65 @@
package org.dromara.pms.domain.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 特殊日期状态枚举
*
* @author ruoyi
* @date 2024-12-19
*/
@Getter
@AllArgsConstructor
public enum SpecialDateStatus {
/**
* 启用
*/
ACTIVE("active", "启用"),
/**
* 禁用
*/
INACTIVE("inactive", "禁用");
/**
* 数据库存储值
*/
private final String code;
/**
* 显示名称
*/
private final String description;
/**
* 根据代码获取枚举
*
* @param code 代码
* @return 枚举值
*/
public static SpecialDateStatus fromCode(String code) {
for (SpecialDateStatus status : values()) {
if (status.getCode().equals(code)) {
return status;
}
}
throw new IllegalArgumentException("未知的特殊日期状态: " + code);
}
/**
* 检查代码是否有效
*
* @param code 代码
* @return 是否有效
*/
public static boolean isValidCode(String code) {
for (SpecialDateStatus status : values()) {
if (status.getCode().equals(code)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,90 @@
package org.dromara.pms.domain.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 特殊日期类型枚举
*
* @author ruoyi
* @date 2024-12-19
*/
@Getter
@AllArgsConstructor
public enum SpecialDateType {
/**
* 法定节假日
*/
LEGAL_HOLIDAY("legal_holiday", "法定节假日"),
/**
* 传统节日
*/
TRADITIONAL_FESTIVAL("traditional_festival", "传统节日"),
/**
* 周末
*/
WEEKEND("weekend", "周末"),
/**
* 促销日
*/
PROMOTION_DAY("promotion_day", "促销日"),
/**
* 特殊活动日
*/
SPECIAL_EVENT("special_event", "特殊活动日"),
/**
* 淡季
*/
LOW_SEASON("low_season", "淡季"),
/**
* 旺季
*/
HIGH_SEASON("high_season", "旺季");
/**
* 数据库存储值
*/
private final String code;
/**
* 显示名称
*/
private final String description;
/**
* 根据代码获取枚举
*
* @param code 代码
* @return 枚举值
*/
public static SpecialDateType fromCode(String code) {
for (SpecialDateType type : values()) {
if (type.getCode().equals(code)) {
return type;
}
}
throw new IllegalArgumentException("未知的特殊日期类型: " + code);
}
/**
* 检查代码是否有效
*
* @param code 代码
* @return 是否有效
*/
public static boolean isValidCode(String code) {
for (SpecialDateType type : values()) {
if (type.getCode().equals(code)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,43 @@
package org.dromara.pms.domain.enums.converter;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.dromara.pms.domain.enums.PriceAdjustmentType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 价格调整类型枚举转换器
*
* @author ruoyi
* @date 2024-12-19
*/
public class PriceAdjustmentTypeConverter extends BaseTypeHandler<PriceAdjustmentType> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, PriceAdjustmentType parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter.getCode());
}
@Override
public PriceAdjustmentType getNullableResult(ResultSet rs, String columnName) throws SQLException {
String code = rs.getString(columnName);
return code == null ? null : PriceAdjustmentType.fromCode(code);
}
@Override
public PriceAdjustmentType getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String code = rs.getString(columnIndex);
return code == null ? null : PriceAdjustmentType.fromCode(code);
}
@Override
public PriceAdjustmentType getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String code = cs.getString(columnIndex);
return code == null ? null : PriceAdjustmentType.fromCode(code);
}
}

View File

@ -0,0 +1,43 @@
package org.dromara.pms.domain.enums.converter;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.dromara.pms.domain.enums.PricingRuleStatus;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 价格规则状态枚举转换器
*
* @author ruoyi
* @date 2024-12-19
*/
public class PricingRuleStatusConverter extends BaseTypeHandler<PricingRuleStatus> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, PricingRuleStatus parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter.getCode());
}
@Override
public PricingRuleStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {
String code = rs.getString(columnName);
return code == null ? null : PricingRuleStatus.fromCode(code);
}
@Override
public PricingRuleStatus getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String code = rs.getString(columnIndex);
return code == null ? null : PricingRuleStatus.fromCode(code);
}
@Override
public PricingRuleStatus getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String code = cs.getString(columnIndex);
return code == null ? null : PricingRuleStatus.fromCode(code);
}
}

View File

@ -0,0 +1,43 @@
package org.dromara.pms.domain.enums.converter;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.dromara.pms.domain.enums.SpecialDateStatus;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 特殊日期状态枚举转换器
*
* @author ruoyi
* @date 2024-12-19
*/
public class SpecialDateStatusConverter extends BaseTypeHandler<SpecialDateStatus> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, SpecialDateStatus parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter.getCode());
}
@Override
public SpecialDateStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {
String code = rs.getString(columnName);
return code == null ? null : SpecialDateStatus.fromCode(code);
}
@Override
public SpecialDateStatus getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String code = rs.getString(columnIndex);
return code == null ? null : SpecialDateStatus.fromCode(code);
}
@Override
public SpecialDateStatus getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String code = cs.getString(columnIndex);
return code == null ? null : SpecialDateStatus.fromCode(code);
}
}

View File

@ -0,0 +1,43 @@
package org.dromara.pms.domain.enums.converter;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.dromara.pms.domain.enums.SpecialDateType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 特殊日期类型枚举转换器
*
* @author ruoyi
* @date 2024-12-19
*/
public class SpecialDateTypeConverter extends BaseTypeHandler<SpecialDateType> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, SpecialDateType parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter.getCode());
}
@Override
public SpecialDateType getNullableResult(ResultSet rs, String columnName) throws SQLException {
String code = rs.getString(columnName);
return code == null ? null : SpecialDateType.fromCode(code);
}
@Override
public SpecialDateType getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String code = rs.getString(columnIndex);
return code == null ? null : SpecialDateType.fromCode(code);
}
@Override
public SpecialDateType getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String code = cs.getString(columnIndex);
return code == null ? null : SpecialDateType.fromCode(code);
}
}

View File

@ -0,0 +1,62 @@
package org.dromara.pms.domain.vo;
import org.dromara.pms.domain.PmsContactTagRelations;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 联系人标签关联视图对象 pms_contact_tag_relations
*
* @author xuhf
* @date 2025-05-24
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsContactTagRelations.class)
public class PmsContactTagRelationsVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 关联唯一ID
*/
@ExcelProperty(value = "关联唯一ID")
private Long relationId;
/**
* 联系人ID
*/
@ExcelProperty(value = "联系人ID")
private Long contactId;
/**
* 标签ID
*/
@ExcelProperty(value = "标签ID")
private Long tagId;
/**
* 联系人姓名关联查询
*/
private String contactName;
/**
* 标签名称关联查询
*/
private String tagName;
/**
* 标签颜色关联查询
*/
private String tagColor;
}

View File

@ -0,0 +1,80 @@
package org.dromara.pms.domain.vo;
import org.dromara.pms.domain.PmsContactTags;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 联系人标签视图对象 pms_contact_tags
*
* @author xuhf
* @date 2025-05-24
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsContactTags.class)
public class PmsContactTagsVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 标签唯一ID
*/
@ExcelProperty(value = "标签唯一ID")
private Long tagId;
/**
* 部门ID (门店, 可空)
*/
@ExcelProperty(value = "部门ID (门店, 可空)")
private Long deptId;
/**
* 标签名称
*/
@ExcelProperty(value = "标签名称")
private String name;
/**
* 标签显示颜色
*/
@ExcelProperty(value = "标签显示颜色")
private String color;
/**
* 标签分类
*/
@ExcelProperty(value = "标签分类")
private String category;
/**
* 标签描述
*/
@ExcelProperty(value = "标签描述")
private String description;
/**
* 是否为系统预设标签
*/
@ExcelProperty(value = "是否为系统预设标签")
private Long isSystem;
/**
* 排序值
*/
@ExcelProperty(value = "排序值")
private Long sortOrder;
}

View File

@ -0,0 +1,182 @@
package org.dromara.pms.domain.vo;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.pms.domain.PmsCustomerContacts;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 客户联系人视图对象 pms_customer_contacts
*
* @author xuhf
* @date 2025-05-24
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsCustomerContacts.class)
public class PmsCustomerContactsVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 联系人唯一ID
*/
@ExcelProperty(value = "联系人唯一ID")
private Long contactId;
/**
* 联系人类型
*/
@ExcelProperty(value = "联系人类型")
private String contactType;
/**
* 联系人姓名
*/
@ExcelProperty(value = "联系人姓名")
private String fullName;
/**
* 主要联系电话
*/
@ExcelProperty(value = "主要联系电话")
private String phoneNumber;
/**
* 电子邮件地址
*/
@ExcelProperty(value = "电子邮件地址")
private String email;
/**
* 微信OpenID
*/
@ExcelProperty(value = "微信OpenID")
private String wechatOpenid;
/**
* 微信UnionID
*/
@ExcelProperty(value = "微信UnionID")
private String wechatUnionid;
/**
* 性别
*/
@ExcelProperty(value = "性别")
private String gender;
/**
* 出生日期
*/
@ExcelProperty(value = "出生日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date dateOfBirth;
/**
* 证件类型
*/
@ExcelProperty(value = "证件类型")
private String idType;
/**
* 证件号码 (加密存储)
*/
@ExcelProperty(value = "证件号码 (加密存储)")
private String idNumberEncrypted;
/**
* 国籍代码
*/
@ExcelProperty(value = "国籍代码")
private String nationalityCountryCode;
/**
* 地址-省份
*/
@ExcelProperty(value = "地址-省份")
private String addressProvince;
/**
* 地址-城市
*/
@ExcelProperty(value = "地址-城市")
private String addressCity;
/**
* 地址-区县
*/
@ExcelProperty(value = "地址-区县")
private String addressDistrict;
/**
* 地址-详细地址
*/
@ExcelProperty(value = "地址-详细地址")
private String addressDetail;
/**
* 邮政编码
*/
@ExcelProperty(value = "邮政编码")
private String postalCode;
/**
* 联系人状态
*/
@ExcelProperty(value = "联系人状态")
private String contactStatus;
/**
* 会员等级
*/
@ExcelProperty(value = "会员等级")
private String memberLevel;
/**
* 总入住次数
*/
@ExcelProperty(value = "总入住次数")
private Long totalStays;
/**
* 总消费金额
*/
@ExcelProperty(value = "总消费金额")
private Long totalAmount;
/**
* 最后入住日期
*/
@ExcelProperty(value = "最后入住日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date lastStayDate;
/**
* 备注信息
*/
@ExcelProperty(value = "备注信息")
private String remarks;
/**
* 关联的标签列表
*/
private List<PmsContactTagsVo> tags;
/**
* 标签ID列表用于编辑时的数据绑定
*/
private List<Long> tagIds;
}

View File

@ -0,0 +1,217 @@
package org.dromara.pms.domain.vo;
import org.dromara.pms.domain.PmsPricingCalculation;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 价格计算历史视图对象 pms_pricing_calculations
*
* @author PMS
* @date 2024-12-01
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsPricingCalculation.class)
public class PmsPricingCalculationVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 计算记录ID
*/
@ExcelProperty(value = "计算记录ID")
private Long calculationId;
/**
* 租户ID
*/
@ExcelProperty(value = "租户ID")
private String tenantId;
/**
* 部门ID (门店)
*/
@ExcelProperty(value = "部门ID")
private Long deptId;
/**
* 房型ID
*/
@ExcelProperty(value = "房型ID")
private Long roomTypeId;
/**
* 房型名称
*/
@ExcelProperty(value = "房型名称")
private String roomTypeName;
/**
* 入住日期
*/
@ExcelProperty(value = "入住日期")
private LocalDate checkInDate;
/**
* 离店日期
*/
@ExcelProperty(value = "离店日期")
private LocalDate checkOutDate;
/**
* 入住天数
*/
@ExcelProperty(value = "入住天数")
private Integer stayDays;
/**
* 成人数
*/
@ExcelProperty(value = "成人数")
private Integer numAdults;
/**
* 儿童数
*/
@ExcelProperty(value = "儿童数")
private Integer numChildren;
/**
* 渠道代码
*/
@ExcelProperty(value = "渠道代码")
private String channelCode;
/**
* 渠道名称
*/
@ExcelProperty(value = "渠道名称")
private String channelName;
/**
* 会员等级
*/
@ExcelProperty(value = "会员等级", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_member_level")
private String memberLevel;
/**
* 提前预订天数
*/
@ExcelProperty(value = "提前预订天数")
private Integer advanceBookingDays;
/**
* 基础价格
*/
@ExcelProperty(value = "基础价格")
private BigDecimal basePrice;
/**
* 最终价格
*/
@ExcelProperty(value = "最终价格")
private BigDecimal finalPrice;
/**
* 总折扣金额
*/
@ExcelProperty(value = "总折扣金额")
private BigDecimal totalDiscount;
/**
* 折扣率
*/
@ExcelProperty(value = "折扣率")
private BigDecimal discountRate;
/**
* 价格变化金额
*/
@ExcelProperty(value = "价格变化金额")
private BigDecimal priceChange;
/**
* 价格变化率
*/
@ExcelProperty(value = "价格变化率")
private BigDecimal priceChangeRate;
/**
* 应用的规则列表
*/
private List<Map<String, Object>> appliedRules;
/**
* 规则数量
*/
@ExcelProperty(value = "应用规则数量")
private Integer ruleCount;
/**
* 计算上下文
*/
private Map<String, Object> calculationContext;
/**
* 计算时间
*/
@ExcelProperty(value = "计算时间")
private LocalDateTime calculationTime;
/**
* 计算来源
*/
@ExcelProperty(value = "计算来源", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_calculation_source")
private String calculationSource;
/**
* 计算来源文本
*/
private String calculationSourceText;
/**
* 关联订单ID
*/
@ExcelProperty(value = "关联订单ID")
private Long orderId;
/**
* 订单号
*/
@ExcelProperty(value = "订单号")
private String orderNumber;
/**
* 是否为最终预订
*/
@ExcelProperty(value = "是否最终预订")
private Boolean isFinalBooking;
/**
* 是否有折扣
*/
private Boolean hasDiscount;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
private Date createTime;
}

View File

@ -0,0 +1,126 @@
package org.dromara.pms.domain.vo;
import org.dromara.pms.domain.PmsRoomLock;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
import java.io.Serializable;
/**
* 房间锁定管理视图对象 pms_room_locks
*
* @author xuhf
* @date 2025-05-28
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsRoomLock.class)
public class PmsRoomLockVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 锁定记录唯一ID
*/
@ExcelProperty(value = "锁定记录唯一ID")
private Long lockId;
/**
* 部门ID (门店)
*/
@ExcelProperty(value = "部门ID")
private Long deptId;
/**
* 部门名称
*/
@ExcelProperty(value = "门店名称")
private String deptName;
/**
* 房间ID
*/
@ExcelProperty(value = "房间ID")
private Long roomId;
/**
* 房间号
*/
@ExcelProperty(value = "房间号")
private String roomNumber;
/**
* 锁定类型
*/
@ExcelProperty(value = "锁定类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_lock_type")
private String lockType;
/**
* 锁定开始时间
*/
@ExcelProperty(value = "锁定开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lockStartTime;
/**
* 锁定结束时间
*/
@ExcelProperty(value = "锁定结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lockEndTime;
/**
* 锁定原因
*/
@ExcelProperty(value = "锁定原因")
private String lockReason;
/**
* 锁定状态
*/
@ExcelProperty(value = "锁定状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_lock_status")
private String lockStatus;
/**
* 解锁时间
*/
@ExcelProperty(value = "解锁时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date unlockTime;
/**
* 解锁操作人
*/
@ExcelProperty(value = "解锁操作人")
private Long unlockBy;
/**
* 解锁操作人姓名
*/
@ExcelProperty(value = "解锁操作人姓名")
private String unlockByName;
/**
* 解锁原因
*/
@ExcelProperty(value = "解锁原因")
private String unlockReason;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}

View File

@ -0,0 +1,255 @@
package org.dromara.pms.domain.vo;
import org.dromara.pms.domain.PmsRoomPricingRule;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
/**
* 房间价格规则视图对象 pms_room_pricing_rules
*
* @author PMS
* @date 2024-12-01
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsRoomPricingRule.class)
public class PmsRoomPricingRuleVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 规则ID
*/
@ExcelProperty(value = "规则ID")
private Long ruleId;
/**
* 租户ID
*/
@ExcelProperty(value = "租户ID")
private String tenantId;
/**
* 部门ID (门店)
*/
@ExcelProperty(value = "部门ID")
private Long deptId;
/**
* 规则名称
*/
@ExcelProperty(value = "规则名称")
private String name;
/**
* 规则描述
*/
@ExcelProperty(value = "规则描述")
private String description;
/**
* 适用房型ID
*/
@ExcelProperty(value = "适用房型ID")
private Long roomTypeId;
/**
* 房型名称
*/
@ExcelProperty(value = "房型名称")
private String roomTypeName;
/**
* 适用日期范围开始
*/
@ExcelProperty(value = "适用开始日期")
private LocalDate dateRangeStart;
/**
* 适用日期范围结束
*/
@ExcelProperty(value = "适用结束日期")
private LocalDate dateRangeEnd;
/**
* 适用星期列表
*/
private List<Integer> daysOfWeek;
/**
* 适用星期显示文本
*/
@ExcelProperty(value = "适用星期")
private String daysOfWeekText;
/**
* 价格调整类型
*/
@ExcelProperty(value = "调整类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_price_adjustment_type")
private String priceAdjustmentType;
/**
* 价格调整类型文本
*/
private String priceAdjustmentTypeText;
/**
* 调整值
*/
@ExcelProperty(value = "调整值")
private BigDecimal adjustmentValue;
/**
* 最小入住天数
*/
@ExcelProperty(value = "最小入住天数")
private Integer minLengthOfStay;
/**
* 最大入住天数
*/
@ExcelProperty(value = "最大入住天数")
private Integer maxLengthOfStay;
/**
* 最小提前预订天数
*/
@ExcelProperty(value = "最小提前预订天数")
private Integer advanceBookingDaysMin;
/**
* 最大提前预订天数
*/
@ExcelProperty(value = "最大提前预订天数")
private Integer advanceBookingDaysMax;
/**
* 渠道限制列表
*/
private List<String> channelRestrictions;
/**
* 渠道限制显示文本
*/
@ExcelProperty(value = "渠道限制")
private String channelRestrictionsText;
/**
* 最小客人数
*/
@ExcelProperty(value = "最小客人数")
private Integer guestCountMin;
/**
* 最大客人数
*/
@ExcelProperty(value = "最大客人数")
private Integer guestCountMax;
/**
* 会员等级限制列表
*/
private List<String> memberLevelRestrictions;
/**
* 会员等级限制显示文本
*/
@ExcelProperty(value = "会员等级限制")
private String memberLevelRestrictionsText;
/**
* 优先级
*/
@ExcelProperty(value = "优先级")
private Integer priority;
/**
* 规则状态
*/
@ExcelProperty(value = "规则状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_rule_status")
private String status;
/**
* 规则状态文本
*/
private String statusText;
/**
* 规则生效开始日期
*/
@ExcelProperty(value = "生效开始日期")
private LocalDate effectiveStartDate;
/**
* 规则生效结束日期
*/
@ExcelProperty(value = "生效结束日期")
private LocalDate effectiveEndDate;
/**
* 最大折扣金额
*/
@ExcelProperty(value = "最大折扣金额")
private BigDecimal maxDiscountAmount;
/**
* 最低最终价格
*/
@ExcelProperty(value = "最低最终价格")
private BigDecimal minFinalPrice;
/**
* 是否可与其他规则组合
*/
@ExcelProperty(value = "可组合")
private Boolean isCombinable;
/**
* 使用次数限制
*/
@ExcelProperty(value = "使用次数限制")
private Integer usageLimit;
/**
* 已使用次数
*/
@ExcelProperty(value = "已使用次数")
private Integer usedCount;
/**
* 剩余使用次数
*/
@ExcelProperty(value = "剩余使用次数")
private Integer remainingUsage;
/**
* 是否生效
*/
private Boolean isEffective;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
private Date createTime;
/**
* 更新时间
*/
@ExcelProperty(value = "更新时间")
private Date updateTime;
}

View File

@ -0,0 +1,131 @@
package org.dromara.pms.domain.vo;
import org.dromara.pms.domain.PmsRoomRoom;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
import java.io.Serializable;
/**
* 房间管理视图对象 pms_room_rooms
*
* @author xuhf
* @date 2025-05-28
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsRoomRoom.class)
public class PmsRoomRoomVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 房间唯一ID
*/
@ExcelProperty(value = "房间唯一ID")
private Long roomId;
/**
* 部门ID (门店)
*/
@ExcelProperty(value = "部门ID")
private Long deptId;
/**
* 部门名称
*/
@ExcelProperty(value = "门店名称")
private String deptName;
/**
* 房型ID
*/
@ExcelProperty(value = "房型ID")
private Long roomTypeId;
/**
* 房型名称
*/
@ExcelProperty(value = "房型名称")
private String typeName;
/**
* 房间号
*/
@ExcelProperty(value = "房间号")
private String roomNumber;
/**
* 楼层
*/
@ExcelProperty(value = "楼层")
private String floor;
/**
* 房间物理状态
*/
@ExcelProperty(value = "房间物理状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_room_status")
private String roomStatus;
/**
* 清洁状态
*/
@ExcelProperty(value = "清洁状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_cleaning_status")
private String cleaningStatus;
/**
* 房间描述
*/
@ExcelProperty(value = "房间描述")
private String description;
/**
* 房间特殊设施
*/
@ExcelProperty(value = "房间特殊设施")
private String specialAmenities;
/**
* 最后清洁时间
*/
@ExcelProperty(value = "最后清洁时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastCleaningTime;
/**
* 最后维护时间
*/
@ExcelProperty(value = "最后维护时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastMaintenanceTime;
/**
* 房间状态备注
*/
@ExcelProperty(value = "房间状态备注")
private String statusRemarks;
/**
* 排序值
*/
@ExcelProperty(value = "排序值")
private Integer sortOrder;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}

View File

@ -0,0 +1,124 @@
package org.dromara.pms.domain.vo;
import org.dromara.pms.domain.PmsRoomType;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.math.BigDecimal;
import java.io.Serial;
import java.io.Serializable;
/**
* 房型管理视图对象 pms_room_types
*
* @author xuhf
* @date 2025-05-28
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsRoomType.class)
public class PmsRoomTypeVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 房型唯一ID
*/
@ExcelProperty(value = "房型唯一ID")
private Long roomTypeId;
/**
* 部门ID (门店)
*/
@ExcelProperty(value = "部门ID")
private Long deptId;
/**
* 房型名称
*/
@ExcelProperty(value = "房型名称")
private String typeName;
/**
* 房型代码
*/
@ExcelProperty(value = "房型代码")
private String typeCode;
/**
* 房型描述
*/
@ExcelProperty(value = "房型描述")
private String description;
/**
* 标准入住人数
*/
@ExcelProperty(value = "标准入住人数")
private Integer standardOccupancy;
/**
* 最大入住人数
*/
@ExcelProperty(value = "最大入住人数")
private Integer maxOccupancy;
/**
* 房间面积(平方米)
*/
@ExcelProperty(value = "房间面积")
private BigDecimal roomArea;
/**
* 床型配置
*/
@ExcelProperty(value = "床型配置")
private String bedConfiguration;
/**
* 房间设施
*/
@ExcelProperty(value = "房间设施")
private String amenities;
/**
* 默认价格
*/
@ExcelProperty(value = "默认价格")
private BigDecimal defaultPrice;
/**
* 房型状态
*/
@ExcelProperty(value = "房型状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_room_type_status")
private String status;
/**
* 排序值
*/
@ExcelProperty(value = "排序值")
private Integer sortOrder;
/**
* 房型图片
*/
@ExcelProperty(value = "房型图片")
private String images;
/**
* 部门名称关联查询
*/
private String deptName;
/**
* 房间数量统计字段
*/
private Integer roomCount;
}

View File

@ -0,0 +1,143 @@
package org.dromara.pms.domain.vo;
import org.dromara.pms.domain.PmsSpecialDatePricing;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
/**
* 特殊日期价格视图对象 pms_special_date_pricing
*
* @author PMS
* @date 2024-12-01
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsSpecialDatePricing.class)
public class PmsSpecialDatePricingVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 特殊日期ID
*/
@ExcelProperty(value = "特殊日期ID")
private Long specialDateId;
/**
* 租户ID
*/
@ExcelProperty(value = "租户ID")
private String tenantId;
/**
* 部门ID (门店)
*/
@ExcelProperty(value = "部门ID")
private Long deptId;
/**
* 房型ID
*/
@ExcelProperty(value = "房型ID")
private Long roomTypeId;
/**
* 房型名称
*/
@ExcelProperty(value = "房型名称")
private String roomTypeName;
/**
* 特殊日期
*/
@ExcelProperty(value = "特殊日期")
private LocalDate specialDate;
/**
* 日期类型
*/
@ExcelProperty(value = "日期类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_special_date_type")
private String dateType;
/**
* 日期类型文本
*/
private String dateTypeText;
/**
* 日期名称
*/
@ExcelProperty(value = "日期名称")
private String dateName;
/**
* 价格调整类型
*/
@ExcelProperty(value = "调整类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_price_adjustment_type")
private String priceAdjustmentType;
/**
* 价格调整类型文本
*/
private String priceAdjustmentTypeText;
/**
* 调整值
*/
@ExcelProperty(value = "调整值")
private BigDecimal adjustmentValue;
/**
* 优先级
*/
@ExcelProperty(value = "优先级")
private Integer priority;
/**
* 状态
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pms_special_date_status")
private String status;
/**
* 状态文本
*/
private String statusText;
/**
* 描述
*/
@ExcelProperty(value = "描述")
private String description;
/**
* 是否生效
*/
private Boolean isEffective;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
private Date createTime;
/**
* 更新时间
*/
@ExcelProperty(value = "更新时间")
private Date updateTime;
}

View File

@ -0,0 +1,173 @@
package org.dromara.pms.domain.vo;
import org.dromara.pms.domain.PmsTenantSetting;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.common.sensitive.annotation.Sensitive;
import org.dromara.common.sensitive.core.SensitiveStrategy;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 租户配置视图对象 pms_tenant_settings
*
* @author PMS
* @date 2024-12-01
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmsTenantSetting.class)
public class PmsTenantSettingVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 配置ID
*/
@ExcelProperty(value = "配置ID")
private Long settingId;
/**
* 租户ID
*/
@ExcelProperty(value = "租户ID")
private String tenantId;
/**
* 部门ID (门店)
*/
@ExcelProperty(value = "部门ID")
private Long deptId;
/**
* 门店名称
*/
@ExcelProperty(value = "门店名称")
@Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId")
private String deptName;
/**
* 配置分组
*/
@ExcelProperty(value = "配置分组")
private String settingGroup;
/**
* 配置键
*/
@ExcelProperty(value = "配置键")
private String settingKey;
/**
* 配置值
*/
@ExcelProperty(value = "配置值")
@Sensitive(strategy = SensitiveStrategy.PASSWORD)
private String settingValue;
/**
* 配置名称
*/
@ExcelProperty(value = "配置名称")
private String settingName;
/**
* 配置描述
*/
@ExcelProperty(value = "配置描述")
private String settingDescription;
/**
* 配置类型
*/
@ExcelProperty(value = "配置类型")
private String settingType;
/**
* 配置类型文本
*/
@ExcelProperty(value = "配置类型")
@Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "pms_setting_type")
private String settingTypeText;
/**
* 是否敏感配置
*/
@ExcelProperty(value = "是否敏感配置")
private Boolean isSensitive;
/**
* 是否可编辑
*/
@ExcelProperty(value = "是否可编辑")
private Boolean isEditable;
/**
* 是否系统配置
*/
@ExcelProperty(value = "是否系统配置")
private Boolean isSystem;
/**
* 排序值
*/
@ExcelProperty(value = "排序值")
private Integer sortOrder;
/**
* 状态
*/
@ExcelProperty(value = "状态")
private String status;
/**
* 状态文本
*/
@ExcelProperty(value = "状态")
@Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "pms_setting_status")
private String statusText;
/**
* 是否继承配置
*/
@ExcelProperty(value = "是否继承配置")
private Boolean isInherited;
/**
* 父级配置值
*/
@ExcelProperty(value = "父级配置值")
private String parentValue;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
private LocalDateTime createTime;
/**
* 更新时间
*/
@ExcelProperty(value = "更新时间")
private LocalDateTime updateTime;
/**
* 创建者
*/
@ExcelProperty(value = "创建者")
@Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
private String createByName;
/**
* 更新者
*/
@ExcelProperty(value = "更新者")
@Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "updateBy")
private String updateByName;
}

View File

@ -0,0 +1,65 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsContactTagRelations;
import org.dromara.pms.domain.vo.PmsContactTagRelationsVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* 联系人标签关联Mapper接口
*
* @author xuhf
* @date 2025-05-24
*/
public interface PmsContactTagRelationsMapper extends BaseMapperPlus<PmsContactTagRelations, PmsContactTagRelationsVo> {
/**
* 根据联系人ID查询标签关联列表
*
* @param contactId 联系人ID
* @return 关联列表
*/
List<PmsContactTagRelationsVo> selectRelationsByContactId(Long contactId);
/**
* 根据标签ID查询关联的联系人列表
*
* @param tagId 标签ID
* @return 关联列表
*/
List<PmsContactTagRelationsVo> selectRelationsByTagId(Long tagId);
/**
* 批量插入联系人标签关联
*
* @param relations 关联列表
* @return 插入数量
*/
int batchInsertRelations(List<PmsContactTagRelations> relations);
/**
* 根据联系人ID删除所有标签关联
*
* @param contactId 联系人ID
* @return 删除数量
*/
int deleteByContactId(Long contactId);
/**
* 根据标签ID删除所有关联
*
* @param tagId 标签ID
* @return 删除数量
*/
int deleteByTagId(Long tagId);
/**
* 检查联系人和标签的关联是否存在
*
* @param contactId 联系人ID
* @param tagId 标签ID
* @return 是否存在
*/
boolean existsRelation(Long contactId, Long tagId);
}

View File

@ -0,0 +1,39 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsContactTags;
import org.dromara.pms.domain.vo.PmsContactTagsVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* 联系人标签Mapper接口
*
* @author xuhf
* @date 2025-05-24
*/
public interface PmsContactTagsMapper extends BaseMapperPlus<PmsContactTags, PmsContactTagsVo> {
/**
* 根据分类查询标签列表
*
* @param category 标签分类
* @return 标签列表
*/
List<PmsContactTagsVo> selectTagsByCategory(String category);
/**
* 查询可用的标签分类列表
*
* @return 分类列表
*/
List<String> selectDistinctCategories();
/**
* 根据部门ID查询标签列表
*
* @param deptId 部门ID
* @return 标签列表
*/
List<PmsContactTagsVo> selectTagsByDeptId(Long deptId);
}

View File

@ -0,0 +1,33 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsCustomerContacts;
import org.dromara.pms.domain.vo.PmsCustomerContactsVo;
import org.dromara.pms.domain.vo.PmsContactTagsVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* 客户联系人Mapper接口
*
* @author xuhf
* @date 2025-05-24
*/
public interface PmsCustomerContactsMapper extends BaseMapperPlus<PmsCustomerContacts, PmsCustomerContactsVo> {
/**
* 查询联系人详情包含标签信息
*
* @param contactId 联系人ID
* @return 联系人详情
*/
PmsCustomerContactsVo selectVoByIdWithTags(Long contactId);
/**
* 查询联系人的标签列表
*
* @param contactId 联系人ID
* @return 标签列表
*/
List<PmsContactTagsVo> selectTagsByContactId(Long contactId);
}

View File

@ -0,0 +1,122 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsPricingCalculation;
import org.dromara.pms.domain.vo.PmsPricingCalculationVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 价格计算历史Mapper接口
*
* @author PMS
* @date 2024-12-01
*/
public interface PmsPricingCalculationMapper extends BaseMapperPlus<PmsPricingCalculation, PmsPricingCalculationVo> {
/**
* 查询价格趋势数据
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 价格趋势数据
*/
List<Map<String, Object>> selectPriceTrend(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("roomTypeId") Long roomTypeId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
/**
* 查询规则效果分析数据
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param ruleId 规则ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 规则效果分析数据
*/
List<Map<String, Object>> selectRuleEffectAnalysis(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("ruleId") Long ruleId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
/**
* 查询收益分析数据
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 收益分析数据
*/
List<Map<String, Object>> selectRevenueAnalysis(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
/**
* 查询平均价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 平均价格
*/
Map<String, Object> selectAveragePrice(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("roomTypeId") Long roomTypeId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
/**
* 查询价格分布统计
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 价格分布统计
*/
List<Map<String, Object>> selectPriceDistribution(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("roomTypeId") Long roomTypeId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
/**
* 查询渠道价格对比
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 渠道价格对比数据
*/
List<Map<String, Object>> selectChannelPriceComparison(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("roomTypeId") Long roomTypeId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
/**
* 删除过期的计算记录
*
* @param beforeDate 删除此日期之前的记录
* @return 删除的记录数
*/
int deleteExpiredRecords(@Param("beforeDate") LocalDateTime beforeDate);
}

View File

@ -0,0 +1,86 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsRoomLock;
import org.dromara.pms.domain.vo.PmsRoomLockVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Date;
/**
* 房间锁定管理Mapper接口
*
* @author xuhf
* @date 2025-05-28
*/
public interface PmsRoomLockMapper extends BaseMapperPlus<PmsRoomLock, PmsRoomLockVo> {
/**
* 根据锁定ID查询锁定详情包含部门名称房间号操作人姓名
*
* @param lockId 锁定ID
* @return 锁定详情
*/
PmsRoomLockVo selectVoByIdWithDetails(@Param("lockId") Long lockId);
/**
* 查询锁定列表包含部门名称房间号操作人姓名
*
* @param lock 锁定查询条件
* @return 锁定列表
*/
List<PmsRoomLockVo> selectVoListWithDetails(PmsRoomLock lock);
/**
* 根据房间ID查询活跃的锁定记录
*
* @param roomId 房间ID
* @return 活跃的锁定记录列表
*/
List<PmsRoomLockVo> selectActiveLocksByRoomId(@Param("roomId") Long roomId);
/**
* 根据部门ID查询锁定列表
*
* @param deptId 部门ID
* @return 锁定列表
*/
List<PmsRoomLockVo> selectByDeptId(@Param("deptId") Long deptId);
/**
* 根据锁定类型查询锁定列表
*
* @param deptId 部门ID
* @param lockType 锁定类型
* @return 锁定列表
*/
List<PmsRoomLockVo> selectByLockType(@Param("deptId") Long deptId,
@Param("lockType") String lockType);
/**
* 查询指定时间范围内的锁定记录
*
* @param deptId 部门ID
* @param startTime 开始时间
* @param endTime 结束时间
* @return 锁定列表
*/
List<PmsRoomLockVo> selectByTimeRange(@Param("deptId") Long deptId,
@Param("startTime") Date startTime,
@Param("endTime") Date endTime);
/**
* 检查房间在指定时间段是否有冲突的锁定
*
* @param roomId 房间ID
* @param startTime 开始时间
* @param endTime 结束时间
* @param excludeId 排除的锁定ID编辑时使用
* @return 冲突的锁定记录数量
*/
int checkTimeConflict(@Param("roomId") Long roomId,
@Param("startTime") Date startTime,
@Param("endTime") Date endTime,
@Param("excludeId") Long excludeId);
}

View File

@ -0,0 +1,98 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsRoomPricingRule;
import org.dromara.pms.domain.vo.PmsRoomPricingRuleVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDate;
import java.util.List;
/**
* 房间价格规则Mapper接口
*
* @author PMS
* @date 2024-12-01
*/
public interface PmsRoomPricingRuleMapper extends BaseMapperPlus<PmsRoomPricingRule, PmsRoomPricingRuleVo> {
/**
* 查询适用的价格规则
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param checkInDate 入住日期
* @param checkOutDate 离店日期
* @param channelCode 渠道代码
* @param memberLevel 会员等级
* @param guestCount 客人数量
* @param advanceBookingDays 提前预订天数
* @return 适用的价格规则列表
*/
List<PmsRoomPricingRule> selectApplicableRules(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("roomTypeId") Long roomTypeId,
@Param("checkInDate") LocalDate checkInDate,
@Param("checkOutDate") LocalDate checkOutDate,
@Param("channelCode") String channelCode,
@Param("memberLevel") String memberLevel,
@Param("guestCount") Integer guestCount,
@Param("advanceBookingDays") Integer advanceBookingDays);
/**
* 查询有效的价格规则
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param status 状态
* @return 有效的价格规则列表
*/
List<PmsRoomPricingRule> selectActiveRules(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("status") String status);
/**
* 查询规则使用统计
*
* @param ruleId 规则ID
* @return 使用统计信息
*/
Integer selectRuleUsageCount(@Param("ruleId") Long ruleId);
/**
* 更新规则使用次数
*
* @param ruleId 规则ID
* @param count 增加的使用次数
* @return 更新结果
*/
int updateRuleUsageCount(@Param("ruleId") Long ruleId, @Param("count") Integer count);
/**
* 查询冲突的价格规则
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param dateRangeStart 开始日期
* @param dateRangeEnd 结束日期
* @param excludeRuleId 排除的规则ID
* @return 冲突的价格规则列表
*/
List<PmsRoomPricingRule> selectConflictingRules(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("roomTypeId") Long roomTypeId,
@Param("dateRangeStart") LocalDate dateRangeStart,
@Param("dateRangeEnd") LocalDate dateRangeEnd,
@Param("excludeRuleId") Long excludeRuleId);
/**
* 批量更新规则状态
*
* @param ruleIds 规则ID列表
* @param status 新状态
* @return 更新结果
*/
int batchUpdateStatus(@Param("ruleIds") List<Long> ruleIds, @Param("status") String status);
}

View File

@ -0,0 +1,73 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsRoomRoom;
import org.dromara.pms.domain.vo.PmsRoomRoomVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 房间管理Mapper接口
*
* @author xuhf
* @date 2025-05-28
*/
public interface PmsRoomRoomMapper extends BaseMapperPlus<PmsRoomRoom, PmsRoomRoomVo> {
/**
* 根据房间ID查询房间详情包含部门名称和房型名称
*
* @param roomId 房间ID
* @return 房间详情
*/
PmsRoomRoomVo selectVoByIdWithDetails(@Param("roomId") Long roomId);
/**
* 查询房间列表包含部门名称和房型名称
*
* @param room 房间查询条件
* @return 房间列表
*/
List<PmsRoomRoomVo> selectVoListWithDetails(PmsRoomRoom room);
/**
* 根据房间号查询房间用于唯一性校验
*
* @param roomNumber 房间号
* @param deptId 部门ID
* @param excludeId 排除的房间ID编辑时使用
* @return 房间信息
*/
PmsRoomRoom selectByRoomNumber(@Param("roomNumber") String roomNumber,
@Param("deptId") Long deptId,
@Param("excludeId") Long excludeId);
/**
* 根据房型ID查询房间列表
*
* @param roomTypeId 房型ID
* @return 房间列表
*/
List<PmsRoomRoomVo> selectByRoomTypeId(@Param("roomTypeId") Long roomTypeId);
/**
* 根据部门ID查询房间列表
*
* @param deptId 部门ID
* @return 房间列表
*/
List<PmsRoomRoomVo> selectByDeptId(@Param("deptId") Long deptId);
/**
* 根据房间状态查询房间列表
*
* @param deptId 部门ID
* @param roomStatus 房间物理状态
* @param cleaningStatus 清洁状态
* @return 房间列表
*/
List<PmsRoomRoomVo> selectByStatus(@Param("deptId") Long deptId,
@Param("roomStatus") String roomStatus,
@Param("cleaningStatus") String cleaningStatus);
}

View File

@ -0,0 +1,53 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsRoomType;
import org.dromara.pms.domain.vo.PmsRoomTypeVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 房型管理Mapper接口
*
* @author xuhf
* @date 2025-05-28
*/
public interface PmsRoomTypeMapper extends BaseMapperPlus<PmsRoomType, PmsRoomTypeVo> {
/**
* 根据房型ID查询房型详情包含部门名称
*
* @param roomTypeId 房型ID
* @return 房型详情
*/
PmsRoomTypeVo selectVoByIdWithDept(@Param("roomTypeId") Long roomTypeId);
/**
* 查询房型列表包含部门名称和房间数量统计
*
* @param roomType 房型查询条件
* @return 房型列表
*/
List<PmsRoomTypeVo> selectVoListWithStats(PmsRoomType roomType);
/**
* 根据房型代码查询房型用于唯一性校验
*
* @param typeCode 房型代码
* @param deptId 部门ID
* @param excludeId 排除的房型ID编辑时使用
* @return 房型信息
*/
PmsRoomType selectByTypeCode(@Param("typeCode") String typeCode,
@Param("deptId") Long deptId,
@Param("excludeId") Long excludeId);
/**
* 根据部门ID查询房型列表
*
* @param deptId 部门ID
* @return 房型列表
*/
List<PmsRoomTypeVo> selectByDeptId(@Param("deptId") Long deptId);
}

View File

@ -0,0 +1,115 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsSpecialDatePricing;
import org.dromara.pms.domain.vo.PmsSpecialDatePricingVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDate;
import java.util.List;
/**
* 特殊日期价格Mapper接口
*
* @author PMS
* @date 2024-12-01
*/
public interface PmsSpecialDatePricingMapper extends BaseMapperPlus<PmsSpecialDatePricing, PmsSpecialDatePricingVo> {
/**
* 查询指定日期范围内的特殊日期价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID (NULL表示全部房型)
* @param startDate 开始日期
* @param endDate 结束日期
* @return 特殊日期价格列表
*/
List<PmsSpecialDatePricing> selectByDateRange(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("roomTypeId") Long roomTypeId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
/**
* 查询指定日期的特殊价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param specialDate 特殊日期
* @return 特殊日期价格
*/
PmsSpecialDatePricing selectByDate(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("roomTypeId") Long roomTypeId,
@Param("specialDate") LocalDate specialDate);
/**
* 查询有效的特殊日期价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param status 状态
* @return 有效的特殊日期价格列表
*/
List<PmsSpecialDatePricing> selectActiveSpecialDates(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("status") String status);
/**
* 查询冲突的特殊日期价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param specialDate 特殊日期
* @param excludeDateId 排除的特殊日期ID
* @return 冲突的特殊日期价格列表
*/
List<PmsSpecialDatePricing> selectConflictingDates(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("roomTypeId") Long roomTypeId,
@Param("specialDate") LocalDate specialDate,
@Param("excludeDateId") Long excludeDateId);
/**
* 批量插入特殊日期价格
*
* @param specialDatePricings 特殊日期价格列表
* @return 插入结果
*/
int batchInsert(@Param("list") List<PmsSpecialDatePricing> specialDatePricings);
/**
* 批量更新特殊日期价格状态
*
* @param dateIds 特殊日期ID列表
* @param status 新状态
* @return 更新结果
*/
int batchUpdateStatus(@Param("dateIds") List<Long> dateIds, @Param("status") String status);
/**
* 查询按日期类型分组的统计信息
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计信息
*/
List<java.util.Map<String, Object>> selectStatsByDateType(@Param("tenantId") String tenantId,
@Param("deptId") Long deptId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
/**
* 删除过期的特殊日期价格
*
* @param beforeDate 删除此日期之前的记录
* @return 删除的记录数
*/
int deleteExpiredDates(@Param("beforeDate") LocalDate beforeDate);
}

View File

@ -0,0 +1,15 @@
package org.dromara.pms.mapper;
import org.dromara.pms.domain.PmsTenantSetting;
import org.dromara.pms.domain.vo.PmsTenantSettingVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 租户配置Mapper接口
*
* @author PMS
* @date 2024-12-01
*/
public interface PmsTenantSettingMapper extends BaseMapperPlus<PmsTenantSetting, PmsTenantSettingVo> {
}

View File

@ -0,0 +1,118 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.vo.PmsContactTagRelationsVo;
import org.dromara.pms.domain.bo.PmsContactTagRelationsBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 联系人标签关联Service接口
*
* @author xuhf
* @date 2025-05-24
*/
public interface IPmsContactTagRelationsService {
/**
* 查询联系人标签关联
*
* @param relationId 主键
* @return 联系人标签关联
*/
PmsContactTagRelationsVo queryById(Long relationId);
/**
* 分页查询联系人标签关联列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 联系人标签关联分页列表
*/
TableDataInfo<PmsContactTagRelationsVo> queryPageList(PmsContactTagRelationsBo bo, PageQuery pageQuery);
/**
* 查询符合条件的联系人标签关联列表
*
* @param bo 查询条件
* @return 联系人标签关联列表
*/
List<PmsContactTagRelationsVo> queryList(PmsContactTagRelationsBo bo);
/**
* 新增联系人标签关联
*
* @param bo 联系人标签关联
* @return 是否新增成功
*/
Boolean insertByBo(PmsContactTagRelationsBo bo);
/**
* 修改联系人标签关联
*
* @param bo 联系人标签关联
* @return 是否修改成功
*/
Boolean updateByBo(PmsContactTagRelationsBo bo);
/**
* 校验并批量删除联系人标签关联信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据联系人ID查询标签关联列表
*
* @param contactId 联系人ID
* @return 关联列表
*/
List<PmsContactTagRelationsVo> queryRelationsByContactId(Long contactId);
/**
* 根据标签ID查询关联的联系人列表
*
* @param tagId 标签ID
* @return 关联列表
*/
List<PmsContactTagRelationsVo> queryRelationsByTagId(Long tagId);
/**
* 批量保存联系人标签关联
*
* @param contactId 联系人ID
* @param tagIds 标签ID列表
* @return 是否保存成功
*/
Boolean batchSaveRelations(Long contactId, List<Long> tagIds);
/**
* 根据联系人ID删除所有标签关联
*
* @param contactId 联系人ID
* @return 是否删除成功
*/
Boolean deleteByContactId(Long contactId);
/**
* 根据标签ID删除所有关联
*
* @param tagId 标签ID
* @return 是否删除成功
*/
Boolean deleteByTagId(Long tagId);
/**
* 检查联系人和标签的关联是否存在
*
* @param contactId 联系人ID
* @param tagId 标签ID
* @return 是否存在
*/
Boolean existsRelation(Long contactId, Long tagId);
}

View File

@ -0,0 +1,98 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.vo.PmsContactTagsVo;
import org.dromara.pms.domain.bo.PmsContactTagsBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 联系人标签Service接口
*
* @author xuhf
* @date 2025-05-24
*/
public interface IPmsContactTagsService {
/**
* 查询联系人标签
*
* @param tagId 主键
* @return 联系人标签
*/
PmsContactTagsVo queryById(Long tagId);
/**
* 分页查询联系人标签列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 联系人标签分页列表
*/
TableDataInfo<PmsContactTagsVo> queryPageList(PmsContactTagsBo bo, PageQuery pageQuery);
/**
* 查询符合条件的联系人标签列表
*
* @param bo 查询条件
* @return 联系人标签列表
*/
List<PmsContactTagsVo> queryList(PmsContactTagsBo bo);
/**
* 新增联系人标签
*
* @param bo 联系人标签
* @return 是否新增成功
*/
Boolean insertByBo(PmsContactTagsBo bo);
/**
* 修改联系人标签
*
* @param bo 联系人标签
* @return 是否修改成功
*/
Boolean updateByBo(PmsContactTagsBo bo);
/**
* 校验并批量删除联系人标签信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据分类查询标签列表
*
* @param category 标签分类
* @return 标签列表
*/
List<PmsContactTagsVo> queryTagsByCategory(String category);
/**
* 查询可用的标签分类列表
*
* @return 分类列表
*/
List<String> queryDistinctCategories();
/**
* 根据部门ID查询标签列表
*
* @param deptId 部门ID
* @return 标签列表
*/
List<PmsContactTagsVo> queryTagsByDeptId(Long deptId);
/**
* 查询所有可用标签用于下拉选择
*
* @return 标签列表
*/
List<PmsContactTagsVo> queryAllAvailableTags();
}

View File

@ -0,0 +1,85 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.vo.PmsCustomerContactsVo;
import org.dromara.pms.domain.bo.PmsCustomerContactsBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 客户联系人Service接口
*
* @author xuhf
* @date 2025-05-24
*/
public interface IPmsCustomerContactsService {
/**
* 查询客户联系人
*
* @param contactId 主键
* @return 客户联系人
*/
PmsCustomerContactsVo queryById(Long contactId);
/**
* 分页查询客户联系人列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 客户联系人分页列表
*/
TableDataInfo<PmsCustomerContactsVo> queryPageList(PmsCustomerContactsBo bo, PageQuery pageQuery);
/**
* 查询符合条件的客户联系人列表
*
* @param bo 查询条件
* @return 客户联系人列表
*/
List<PmsCustomerContactsVo> queryList(PmsCustomerContactsBo bo);
/**
* 新增客户联系人
*
* @param bo 客户联系人
* @return 是否新增成功
*/
Boolean insertByBo(PmsCustomerContactsBo bo);
/**
* 修改客户联系人
*
* @param bo 客户联系人
* @return 是否修改成功
*/
Boolean updateByBo(PmsCustomerContactsBo bo);
/**
* 校验并批量删除客户联系人信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 保存联系人标签关联
*
* @param contactId 联系人ID
* @param tagIds 标签ID列表
* @return 是否保存成功
*/
Boolean saveContactTags(Long contactId, List<Long> tagIds);
/**
* 查询联系人详情包含标签信息
*
* @param contactId 联系人ID
* @return 联系人详情
*/
PmsCustomerContactsVo queryByIdWithTags(Long contactId);
}

View File

@ -0,0 +1,173 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.vo.PmsPricingCalculationVo;
import org.dromara.pms.domain.bo.PmsPricingCalculationBo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 价格计算历史Service接口
*
* @author PMS
* @date 2024-12-01
*/
public interface IPmsPricingCalculationService {
/**
* 查询价格计算历史
*/
PmsPricingCalculationVo queryById(Long calculationId);
/**
* 查询价格计算历史列表
*/
TableDataInfo<PmsPricingCalculationVo> queryPageList(PmsPricingCalculationBo bo, PageQuery pageQuery);
/**
* 查询价格计算历史列表
*/
List<PmsPricingCalculationVo> queryList(PmsPricingCalculationBo bo);
/**
* 新增价格计算历史
*/
Boolean insertByBo(PmsPricingCalculationBo bo);
/**
* 修改价格计算历史
*/
Boolean updateByBo(PmsPricingCalculationBo bo);
/**
* 校验并批量删除价格计算历史信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 计算房间价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param checkInDate 入住日期
* @param checkOutDate 离店日期
* @param numAdults 成人数
* @param numChildren 儿童数
* @param channelCode 渠道代码
* @param memberLevel 会员等级
* @param advanceBookingDays 提前预订天数
* @param saveHistory 是否保存计算历史
* @return 价格计算结果
*/
Map<String, Object> calculatePrice(String tenantId, Long deptId, Long roomTypeId,
LocalDate checkInDate, LocalDate checkOutDate, Integer numAdults, Integer numChildren,
String channelCode, String memberLevel, Integer advanceBookingDays, Boolean saveHistory);
/**
* 批量计算价格
*
* @param calculations 计算参数列表
* @return 计算结果列表
*/
List<Map<String, Object>> batchCalculatePrice(List<PmsPricingCalculationBo> calculations);
/**
* 查询价格趋势数据
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 价格趋势数据
*/
List<Map<String, Object>> getPriceTrend(String tenantId, Long deptId, Long roomTypeId,
LocalDate startDate, LocalDate endDate);
/**
* 查询规则效果分析数据
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param ruleId 规则ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 规则效果分析数据
*/
List<Map<String, Object>> getRuleEffectAnalysis(String tenantId, Long deptId, Long ruleId,
LocalDate startDate, LocalDate endDate);
/**
* 查询收益分析数据
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 收益分析数据
*/
List<Map<String, Object>> getRevenueAnalysis(String tenantId, Long deptId,
LocalDate startDate, LocalDate endDate);
/**
* 查询平均价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 平均价格信息
*/
Map<String, Object> getAveragePrice(String tenantId, Long deptId, Long roomTypeId,
LocalDate startDate, LocalDate endDate);
/**
* 查询价格分布统计
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 价格分布统计
*/
List<Map<String, Object>> getPriceDistribution(String tenantId, Long deptId, Long roomTypeId,
LocalDate startDate, LocalDate endDate);
/**
* 查询渠道价格对比
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 渠道价格对比数据
*/
List<Map<String, Object>> getChannelPriceComparison(String tenantId, Long deptId, Long roomTypeId,
LocalDate startDate, LocalDate endDate);
/**
* 清理过期的计算记录
*
* @param beforeDate 删除此日期之前的记录
* @return 删除的记录数
*/
Integer cleanExpiredRecords(LocalDateTime beforeDate);
/**
* 导出价格计算历史数据
*
* @param bo 查询条件
* @return 导出数据
*/
List<PmsPricingCalculationVo> exportList(PmsPricingCalculationBo bo);
}

View File

@ -0,0 +1,90 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.vo.PmsRoomLockVo;
import org.dromara.pms.domain.bo.PmsRoomLockBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
import java.util.Date;
/**
* 房间锁定管理Service接口
*
* @author xuhf
* @date 2025-05-28
*/
public interface IPmsRoomLockService {
/**
* 查询房间锁定管理
*/
PmsRoomLockVo queryById(Long lockId);
/**
* 查询房间锁定管理列表
*/
TableDataInfo<PmsRoomLockVo> queryPageList(PmsRoomLockBo bo, PageQuery pageQuery);
/**
* 查询房间锁定管理列表
*/
List<PmsRoomLockVo> queryList(PmsRoomLockBo bo);
/**
* 新增房间锁定管理
*/
Boolean insertByBo(PmsRoomLockBo bo);
/**
* 修改房间锁定管理
*/
Boolean updateByBo(PmsRoomLockBo bo);
/**
* 校验并批量删除房间锁定管理信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据房间ID查询活跃的锁定记录
*/
List<PmsRoomLockVo> queryActiveLocksByRoomId(Long roomId);
/**
* 根据部门ID查询锁定列表
*/
List<PmsRoomLockVo> queryByDeptId(Long deptId);
/**
* 根据锁定类型查询锁定列表
*/
List<PmsRoomLockVo> queryByLockType(Long deptId, String lockType);
/**
* 查询指定时间范围内的锁定记录
*/
List<PmsRoomLockVo> queryByTimeRange(Long deptId, Date startTime, Date endTime);
/**
* 检查房间在指定时间段是否有冲突的锁定
*/
Boolean checkTimeConflict(Long roomId, Date startTime, Date endTime, Long excludeId);
/**
* 解锁房间
*/
Boolean unlockRoom(Long lockId, String unlockReason);
/**
* 批量解锁房间
*/
Boolean batchUnlockRooms(List<Long> lockIds, String unlockReason);
/**
* 自动过期锁定记录
*/
Boolean autoExpireLocks();
}

View File

@ -0,0 +1,136 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.PmsRoomPricingRule;
import org.dromara.pms.domain.vo.PmsRoomPricingRuleVo;
import org.dromara.pms.domain.bo.PmsRoomPricingRuleBo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
/**
* 房间价格规则Service接口
*
* @author PMS
* @date 2024-12-01
*/
public interface IPmsRoomPricingRuleService {
/**
* 查询房间价格规则
*/
PmsRoomPricingRuleVo queryById(Long ruleId);
/**
* 查询房间价格规则列表
*/
TableDataInfo<PmsRoomPricingRuleVo> queryPageList(PmsRoomPricingRuleBo bo, PageQuery pageQuery);
/**
* 查询房间价格规则列表
*/
List<PmsRoomPricingRuleVo> queryList(PmsRoomPricingRuleBo bo);
/**
* 新增房间价格规则
*/
Boolean insertByBo(PmsRoomPricingRuleBo bo);
/**
* 修改房间价格规则
*/
Boolean updateByBo(PmsRoomPricingRuleBo bo);
/**
* 校验并批量删除房间价格规则信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 查询适用的价格规则
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param checkInDate 入住日期
* @param checkOutDate 离店日期
* @param channelCode 渠道代码
* @param memberLevel 会员等级
* @param guestCount 客人数量
* @param advanceBookingDays 提前预订天数
* @return 适用的价格规则列表
*/
List<PmsRoomPricingRule> getApplicableRules(String tenantId, Long deptId, Long roomTypeId,
LocalDate checkInDate, LocalDate checkOutDate, String channelCode,
String memberLevel, Integer guestCount, Integer advanceBookingDays);
/**
* 查询有效的价格规则
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @return 有效的价格规则列表
*/
List<PmsRoomPricingRule> getActiveRules(String tenantId, Long deptId);
/**
* 更新规则使用次数
*
* @param ruleId 规则ID
* @param count 增加的使用次数
* @return 更新结果
*/
Boolean updateRuleUsageCount(Long ruleId, Integer count);
/**
* 检查规则冲突
*
* @param bo 价格规则业务对象
* @return 是否存在冲突
*/
Boolean checkRuleConflict(PmsRoomPricingRuleBo bo);
/**
* 批量更新规则状态
*
* @param ruleIds 规则ID列表
* @param status 新状态
* @return 更新结果
*/
Boolean batchUpdateStatus(List<Long> ruleIds, String status);
/**
* 启用规则
*
* @param ruleId 规则ID
* @return 操作结果
*/
Boolean enableRule(Long ruleId);
/**
* 禁用规则
*
* @param ruleId 规则ID
* @return 操作结果
*/
Boolean disableRule(Long ruleId);
/**
* 复制规则
*
* @param ruleId 源规则ID
* @param newName 新规则名称
* @return 操作结果
*/
Boolean copyRule(Long ruleId, String newName);
/**
* 导出价格规则数据
*
* @param bo 查询条件
* @return 导出数据
*/
List<PmsRoomPricingRuleVo> exportList(PmsRoomPricingRuleBo bo);
}

View File

@ -0,0 +1,84 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.vo.PmsRoomRoomVo;
import org.dromara.pms.domain.bo.PmsRoomRoomBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 房间管理Service接口
*
* @author xuhf
* @date 2025-05-28
*/
public interface IPmsRoomRoomService {
/**
* 查询房间管理
*/
PmsRoomRoomVo queryById(Long roomId);
/**
* 查询房间管理列表
*/
TableDataInfo<PmsRoomRoomVo> queryPageList(PmsRoomRoomBo bo, PageQuery pageQuery);
/**
* 查询房间管理列表
*/
List<PmsRoomRoomVo> queryList(PmsRoomRoomBo bo);
/**
* 新增房间管理
*/
Boolean insertByBo(PmsRoomRoomBo bo);
/**
* 修改房间管理
*/
Boolean updateByBo(PmsRoomRoomBo bo);
/**
* 校验并批量删除房间管理信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据房型ID查询房间列表
*/
List<PmsRoomRoomVo> queryByRoomTypeId(Long roomTypeId);
/**
* 根据部门ID查询房间列表
*/
List<PmsRoomRoomVo> queryByDeptId(Long deptId);
/**
* 根据房间状态查询房间列表
*/
List<PmsRoomRoomVo> queryByStatus(Long deptId, String roomStatus, String cleaningStatus);
/**
* 更新房间状态
*/
Boolean updateRoomStatus(Long roomId, String roomStatus, String statusRemarks);
/**
* 更新清洁状态
*/
Boolean updateCleaningStatus(Long roomId, String cleaningStatus);
/**
* 批量更新房间状态
*/
Boolean batchUpdateRoomStatus(List<Long> roomIds, String roomStatus, String statusRemarks);
/**
* 批量更新清洁状态
*/
Boolean batchUpdateCleaningStatus(List<Long> roomIds, String cleaningStatus);
}

View File

@ -0,0 +1,96 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.vo.PmsRoomTypeVo;
import org.dromara.pms.domain.bo.PmsRoomTypeBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 房型管理Service接口
*
* @author xuhf
* @date 2025-05-28
*/
public interface IPmsRoomTypeService {
/**
* 查询房型管理
*
* @param roomTypeId 房型管理主键
* @return 房型管理
*/
PmsRoomTypeVo queryById(Long roomTypeId);
/**
* 查询房型管理列表
*
* @param bo 房型管理
* @param pageQuery 分页查询
* @return 房型管理集合
*/
TableDataInfo<PmsRoomTypeVo> queryPageList(PmsRoomTypeBo bo, PageQuery pageQuery);
/**
* 查询房型管理列表
*
* @param bo 房型管理
* @return 房型管理集合
*/
List<PmsRoomTypeVo> queryList(PmsRoomTypeBo bo);
/**
* 新增房型管理
*
* @param bo 房型管理
* @return 结果
*/
Boolean insertByBo(PmsRoomTypeBo bo);
/**
* 修改房型管理
*
* @param bo 房型管理
* @return 结果
*/
Boolean updateByBo(PmsRoomTypeBo bo);
/**
* 校验并批量删除房型管理信息
*
* @param ids 需要删除的房型管理主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return 结果
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据部门ID查询房型列表
*
* @param deptId 部门ID
* @return 房型列表
*/
List<PmsRoomTypeVo> queryByDeptId(Long deptId);
/**
* 校验房型代码唯一性
*
* @param typeCode 房型代码
* @param deptId 部门ID
* @param roomTypeId 房型ID编辑时排除自己
* @return 是否唯一
*/
Boolean checkTypeCodeUnique(String typeCode, Long deptId, Long roomTypeId);
/**
* 获取房型选项列表用于下拉选择
*
* @param deptId 部门ID可选
* @return 房型选项列表
*/
List<Map<String, Object>> getOptions(Long deptId);
}

View File

@ -0,0 +1,163 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.PmsSpecialDatePricing;
import org.dromara.pms.domain.vo.PmsSpecialDatePricingVo;
import org.dromara.pms.domain.bo.PmsSpecialDatePricingBo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 特殊日期价格Service接口
*
* @author PMS
* @date 2024-12-01
*/
public interface IPmsSpecialDatePricingService {
/**
* 查询特殊日期价格
*/
PmsSpecialDatePricingVo queryById(Long specialDateId);
/**
* 查询特殊日期价格列表
*/
TableDataInfo<PmsSpecialDatePricingVo> queryPageList(PmsSpecialDatePricingBo bo, PageQuery pageQuery);
/**
* 查询特殊日期价格列表
*/
List<PmsSpecialDatePricingVo> queryList(PmsSpecialDatePricingBo bo);
/**
* 新增特殊日期价格
*/
Boolean insertByBo(PmsSpecialDatePricingBo bo);
/**
* 修改特殊日期价格
*/
Boolean updateByBo(PmsSpecialDatePricingBo bo);
/**
* 校验并批量删除特殊日期价格信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 查询指定日期范围内的特殊日期价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 特殊日期价格列表
*/
List<PmsSpecialDatePricing> getSpecialDatesByRange(String tenantId, Long deptId, Long roomTypeId,
LocalDate startDate, LocalDate endDate);
/**
* 查询指定日期的特殊价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param roomTypeId 房型ID
* @param specialDate 特殊日期
* @return 特殊日期价格
*/
PmsSpecialDatePricing getSpecialDateByDate(String tenantId, Long deptId, Long roomTypeId,
LocalDate specialDate);
/**
* 查询有效的特殊日期价格
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @return 有效的特殊日期价格列表
*/
List<PmsSpecialDatePricing> getActiveSpecialDates(String tenantId, Long deptId);
/**
* 检查特殊日期冲突
*
* @param bo 特殊日期价格业务对象
* @return 是否存在冲突
*/
Boolean checkDateConflict(PmsSpecialDatePricingBo bo);
/**
* 批量设置特殊日期价格
*
* @param specialDates 特殊日期价格列表
* @return 操作结果
*/
Boolean batchInsertSpecialDates(List<PmsSpecialDatePricingBo> specialDates);
/**
* 批量更新特殊日期价格状态
*
* @param dateIds 特殊日期ID列表
* @param status 新状态
* @return 更新结果
*/
Boolean batchUpdateStatus(List<Long> dateIds, String status);
/**
* 启用特殊日期价格
*
* @param specialDateId 特殊日期ID
* @return 操作结果
*/
Boolean enableSpecialDate(Long specialDateId);
/**
* 禁用特殊日期价格
*
* @param specialDateId 特殊日期ID
* @return 操作结果
*/
Boolean disableSpecialDate(Long specialDateId);
/**
* 复制特殊日期价格到其他日期
*
* @param sourceId 源特殊日期ID
* @param targetDate 目标日期
* @return 操作结果
*/
Boolean copySpecialDate(Long sourceId, LocalDate targetDate);
/**
* 查询按日期类型分组的统计信息
*
* @param tenantId 租户ID
* @param deptId 部门ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计信息
*/
List<Map<String, Object>> getStatsByDateType(String tenantId, Long deptId,
LocalDate startDate, LocalDate endDate);
/**
* 清理过期的特殊日期价格
*
* @param beforeDate 删除此日期之前的记录
* @return 删除的记录数
*/
Integer cleanExpiredDates(LocalDate beforeDate);
/**
* 导出特殊日期价格数据
*
* @param bo 查询条件
* @return 导出数据
*/
List<PmsSpecialDatePricingVo> exportList(PmsSpecialDatePricingBo bo);
}

View File

@ -0,0 +1,109 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.vo.PmsTenantSettingVo;
import org.dromara.pms.domain.bo.PmsTenantSettingBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 租户配置Service接口
*
* @author PMS
* @date 2024-12-01
*/
public interface IPmsTenantSettingService {
/**
* 查询租户配置
*/
PmsTenantSettingVo queryById(Long settingId);
/**
* 查询租户配置列表
*/
TableDataInfo<PmsTenantSettingVo> queryPageList(PmsTenantSettingBo bo, PageQuery pageQuery);
/**
* 查询租户配置列表
*/
List<PmsTenantSettingVo> queryList(PmsTenantSettingBo bo);
/**
* 新增租户配置
*/
Boolean insertByBo(PmsTenantSettingBo bo);
/**
* 修改租户配置
*/
Boolean updateByBo(PmsTenantSettingBo bo);
/**
* 校验并批量删除租户配置信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据配置键获取配置值
*/
String getSettingValue(String settingKey);
/**
* 根据配置键获取配置值支持门店级继承
*/
String getSettingValue(String settingKey, Long deptId);
/**
* 根据配置分组获取配置
*/
Map<String, String> getSettingsByGroup(String settingGroup);
/**
* 根据配置分组获取配置支持门店级继承
*/
Map<String, String> getSettingsByGroup(String settingGroup, Long deptId);
/**
* 批量更新配置
*/
Boolean batchUpdateSettings(Map<String, String> settings);
/**
* 批量更新配置支持门店级
*/
Boolean batchUpdateSettings(Map<String, String> settings, Long deptId);
/**
* 重置门店配置为租户默认配置
*/
Boolean resetDeptSettings(Long deptId, String settingGroup);
/**
* 复制租户配置到门店
*/
Boolean copyTenantSettingsToDept(Long deptId, String settingGroup);
/**
* 获取配置继承关系
*/
List<PmsTenantSettingVo> getSettingInheritance(String settingKey);
/**
* 验证配置值格式
*/
Boolean validateSettingValue(String settingType, String settingValue);
/**
* 加密敏感配置值
*/
String encryptSensitiveValue(String value);
/**
* 解密敏感配置值
*/
String decryptSensitiveValue(String encryptedValue);
}

View File

@ -0,0 +1,301 @@
package org.dromara.pms.service;
import org.dromara.pms.domain.PmsRoomPricingRule;
import org.dromara.pms.domain.PmsPricingCalculation;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
/**
* 价格计算服务接口
*
* @author PMS
* @date 2024-12-01
*/
public interface IPricingService {
/**
* 价格计算请求参数
*/
class PricingRequest {
private Long roomTypeId;
private LocalDate checkInDate;
private LocalDate checkOutDate;
private Integer numAdults;
private Integer numChildren;
private String channelCode;
private String memberLevel;
private BigDecimal basePrice;
private String calculationSource;
private Long orderId;
private Boolean isFinalBooking;
// Getters and Setters
public Long getRoomTypeId() {
return roomTypeId;
}
public void setRoomTypeId(Long roomTypeId) {
this.roomTypeId = roomTypeId;
}
public LocalDate getCheckInDate() {
return checkInDate;
}
public void setCheckInDate(LocalDate checkInDate) {
this.checkInDate = checkInDate;
}
public LocalDate getCheckOutDate() {
return checkOutDate;
}
public void setCheckOutDate(LocalDate checkOutDate) {
this.checkOutDate = checkOutDate;
}
public Integer getNumAdults() {
return numAdults;
}
public void setNumAdults(Integer numAdults) {
this.numAdults = numAdults;
}
public Integer getNumChildren() {
return numChildren;
}
public void setNumChildren(Integer numChildren) {
this.numChildren = numChildren;
}
public String getChannelCode() {
return channelCode;
}
public void setChannelCode(String channelCode) {
this.channelCode = channelCode;
}
public String getMemberLevel() {
return memberLevel;
}
public void setMemberLevel(String memberLevel) {
this.memberLevel = memberLevel;
}
public BigDecimal getBasePrice() {
return basePrice;
}
public void setBasePrice(BigDecimal basePrice) {
this.basePrice = basePrice;
}
public String getCalculationSource() {
return calculationSource;
}
public void setCalculationSource(String calculationSource) {
this.calculationSource = calculationSource;
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public Boolean getIsFinalBooking() {
return isFinalBooking;
}
public void setIsFinalBooking(Boolean isFinalBooking) {
this.isFinalBooking = isFinalBooking;
}
}
/**
* 价格计算结果
*/
class PricingResult {
private BigDecimal basePrice;
private BigDecimal finalPrice;
private BigDecimal totalDiscount;
private BigDecimal discountRate;
private List<Map<String, Object>> appliedRules;
private Map<String, Object> calculationContext;
private Boolean success;
private String errorMessage;
// Getters and Setters
public BigDecimal getBasePrice() {
return basePrice;
}
public void setBasePrice(BigDecimal basePrice) {
this.basePrice = basePrice;
}
public BigDecimal getFinalPrice() {
return finalPrice;
}
public void setFinalPrice(BigDecimal finalPrice) {
this.finalPrice = finalPrice;
}
public BigDecimal getTotalDiscount() {
return totalDiscount;
}
public void setTotalDiscount(BigDecimal totalDiscount) {
this.totalDiscount = totalDiscount;
}
public BigDecimal getDiscountRate() {
return discountRate;
}
public void setDiscountRate(BigDecimal discountRate) {
this.discountRate = discountRate;
}
public List<Map<String, Object>> getAppliedRules() {
return appliedRules;
}
public void setAppliedRules(List<Map<String, Object>> appliedRules) {
this.appliedRules = appliedRules;
}
public Map<String, Object> getCalculationContext() {
return calculationContext;
}
public void setCalculationContext(Map<String, Object> calculationContext) {
this.calculationContext = calculationContext;
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
/**
* 计算房间价格
*
* @param request 价格计算请求参数
* @return 价格计算结果
*/
PricingResult calculatePrice(PricingRequest request);
/**
* 批量计算价格
*
* @param requests 价格计算请求列表
* @return 价格计算结果列表
*/
List<PricingResult> batchCalculatePrice(List<PricingRequest> requests);
/**
* 获取适用的价格规则
*
* @param request 价格计算请求参数
* @return 适用的价格规则列表
*/
List<PmsRoomPricingRule> getApplicableRules(PricingRequest request);
/**
* 测试价格规则
*
* @param ruleId 规则ID
* @param request 测试请求参数
* @return 测试结果
*/
PricingResult testRule(Long ruleId, PricingRequest request);
/**
* 模拟价格计算
*
* @param request 价格计算请求参数
* @param simulateRules 模拟的规则列表
* @return 模拟计算结果
*/
PricingResult simulateCalculation(PricingRequest request, List<PmsRoomPricingRule> simulateRules);
/**
* 保存价格计算历史
*
* @param request 价格计算请求参数
* @param result 价格计算结果
* @return 保存的计算历史记录
*/
PmsPricingCalculation savePricingHistory(PricingRequest request, PricingResult result);
/**
* 获取价格趋势分析
*
* @param roomTypeId 房型ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 价格趋势数据
*/
Map<String, Object> getPriceTrendAnalysis(Long roomTypeId, LocalDate startDate, LocalDate endDate);
/**
* 获取规则效果分析
*
* @param ruleId 规则ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 规则效果分析数据
*/
Map<String, Object> getRuleEffectAnalysis(Long ruleId, LocalDate startDate, LocalDate endDate);
/**
* 获取收益分析
*
* @param deptId 部门ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 收益分析数据
*/
Map<String, Object> getRevenueAnalysis(Long deptId, LocalDate startDate, LocalDate endDate);
/**
* 验证价格规则配置
*
* @param rule 价格规则
* @return 验证结果
*/
Map<String, Object> validateRule(PmsRoomPricingRule rule);
/**
* 复制价格规则
*
* @param sourceRuleId 源规则ID
* @param newRuleName 新规则名称
* @return 复制的规则
*/
PmsRoomPricingRule copyRule(Long sourceRuleId, String newRuleName);
}

Some files were not shown because too many files have changed in this diff Show More