提交 docker 部署

This commit is contained in:
wanglongjie 2026-01-27 11:54:11 +08:00
parent e706c48d23
commit 4eefc9fca6
16 changed files with 3023 additions and 117 deletions

31
.gitignore vendored
View File

@ -24,3 +24,34 @@
/backend/target/ /backend/target/
/mysql/data/
# Maven
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
# IDE
.idea/
*.iml
.vscode/
.eclipse/
# Logs
*.log
logs/
# OS
.DS_Store
Thumbs.db
# Git
.git/
.gitignore
# Docker
Dockerfile
.dockerignore

View File

@ -12,7 +12,7 @@ COPY src ./src
RUN mvn clean package -DskipTests RUN mvn clean package -DskipTests
# 运行阶段 # 运行阶段
FROM openjdk:8-jre-alpine FROM eclipse-temurin:8-jre
WORKDIR /app WORKDIR /app

View File

@ -17,11 +17,15 @@ services:
MYSQL_ROOT_PASSWORD: MySQL123s56 MYSQL_ROOT_PASSWORD: MySQL123s56
MYSQL_DATABASE: crm_db MYSQL_DATABASE: crm_db
TZ: Asia/Shanghai TZ: Asia/Shanghai
command: [
'--character-set-server=utf8mb4',
'--collation-server=utf8mb4_unicode_ci',
]
ports: ports:
- "3306:3306" - "3307:3306"
volumes: volumes:
- ./mysql/data:/var/lib/mysql - ./mysql/data:/var/lib/mysql
- ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro - ./sql:/docker-entrypoint-initdb.d:ro
networks: networks:
- crm_network - crm_network
healthcheck: healthcheck:
@ -48,7 +52,7 @@ services:
SPRING_DATASOURCE_PASSWORD: MySQL123s56 SPRING_DATASOURCE_PASSWORD: MySQL123s56
# JWT 配置 # JWT 配置
JWT_SECRET: your-secret-key-change-in-production JWT_SECRET: by-crm-jwt-secret-key-2024-hs512-requires-at-least-64-bytes-for-secure-signing-please-change-in-production-environment
JWT_EXPIRATION: 86400000 JWT_EXPIRATION: 86400000
# 应用配置 # 应用配置

View File

@ -29,7 +29,6 @@ Thumbs.db
# Docker # Docker
Dockerfile Dockerfile
.dockerignore .dockerignore
nginx.conf
# Logs # Logs
*.log *.log

View File

@ -32,7 +32,7 @@
"sass": "^1.69.0", "sass": "^1.69.0",
"typescript": "^5.3.0", "typescript": "^5.3.0",
"vite": "^5.0.0", "vite": "^5.0.0",
"vue-tsc": "^1.8.0" "vue-tsc": "^3.2.4"
}, },
"engines": { "engines": {
"node": ">=16.0.0", "node": ">=16.0.0",

View File

@ -70,8 +70,8 @@ importers:
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.4.21(@types/node@20.19.30)(sass@1.97.3) version: 5.4.21(@types/node@20.19.30)(sass@1.97.3)
vue-tsc: vue-tsc:
specifier: ^1.8.0 specifier: ^3.2.4
version: 1.8.27(typescript@5.9.3) version: 3.2.4(typescript@5.9.3)
packages: packages:
@ -597,14 +597,14 @@ packages:
vite: ^5.0.0 || ^6.0.0 vite: ^5.0.0 || ^6.0.0
vue: ^3.2.25 vue: ^3.2.25
'@volar/language-core@1.11.1': '@volar/language-core@2.4.27':
resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==} resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==}
'@volar/source-map@1.11.1': '@volar/source-map@2.4.27':
resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==} resolution: {integrity: sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==}
'@volar/typescript@1.11.1': '@volar/typescript@2.4.27':
resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==} resolution: {integrity: sha512-eWaYCcl/uAPInSK2Lze6IqVWaBu/itVqR5InXcHXFyles4zO++Mglt3oxdgj75BDcv1Knr9Y93nowS8U3wqhxg==}
'@vue/compiler-core@3.5.27': '@vue/compiler-core@3.5.27':
resolution: {integrity: sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==} resolution: {integrity: sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==}
@ -621,13 +621,8 @@ packages:
'@vue/devtools-api@6.6.4': '@vue/devtools-api@6.6.4':
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
'@vue/language-core@1.8.27': '@vue/language-core@3.2.4':
resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==} resolution: {integrity: sha512-bqBGuSG4KZM45KKTXzGtoCl9cWju5jsaBKaJJe3h5hRAAWpZUuj5G+L+eI01sPIkm4H6setKRlw7E85wLdDNew==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@vue/reactivity@3.5.27': '@vue/reactivity@3.5.27':
resolution: {integrity: sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==} resolution: {integrity: sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==}
@ -668,6 +663,9 @@ packages:
ajv@6.12.6: ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
alien-signals@3.1.2:
resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==}
ansi-regex@5.0.1: ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -739,9 +737,6 @@ packages:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
computeds@0.0.1:
resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
concat-map@0.0.1: concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@ -760,9 +755,6 @@ packages:
dayjs@1.11.19: dayjs@1.11.19:
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
de-indent@1.0.2:
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
debug@4.4.3: debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@ -982,10 +974,6 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
ignore@5.3.2: ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
@ -1100,15 +1088,11 @@ packages:
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
ms@2.1.3: ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
muggle-string@0.3.1: muggle-string@0.4.1:
resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
nanoid@3.3.11: nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
@ -1346,6 +1330,9 @@ packages:
terser: terser:
optional: true optional: true
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
vue-demi@0.14.10: vue-demi@0.14.10:
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -1368,14 +1355,11 @@ packages:
peerDependencies: peerDependencies:
vue: ^3.5.0 vue: ^3.5.0
vue-template-compiler@2.7.16: vue-tsc@3.2.4:
resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==} resolution: {integrity: sha512-xj3YCvSLNDKt1iF9OcImWHhmYcihVu9p4b9s4PGR/qp6yhW+tZJaypGxHScRyOrdnHvaOeF+YkZOdKwbgGvp5g==}
vue-tsc@1.8.27:
resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
typescript: '*' typescript: '>=5.0.0'
vue@3.5.27: vue@3.5.27:
resolution: {integrity: sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==} resolution: {integrity: sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==}
@ -1808,18 +1792,17 @@ snapshots:
vite: 5.4.21(@types/node@20.19.30)(sass@1.97.3) vite: 5.4.21(@types/node@20.19.30)(sass@1.97.3)
vue: 3.5.27(typescript@5.9.3) vue: 3.5.27(typescript@5.9.3)
'@volar/language-core@1.11.1': '@volar/language-core@2.4.27':
dependencies: dependencies:
'@volar/source-map': 1.11.1 '@volar/source-map': 2.4.27
'@volar/source-map@1.11.1': '@volar/source-map@2.4.27': {}
dependencies:
muggle-string: 0.3.1
'@volar/typescript@1.11.1': '@volar/typescript@2.4.27':
dependencies: dependencies:
'@volar/language-core': 1.11.1 '@volar/language-core': 2.4.27
path-browserify: 1.0.1 path-browserify: 1.0.1
vscode-uri: 3.1.0
'@vue/compiler-core@3.5.27': '@vue/compiler-core@3.5.27':
dependencies: dependencies:
@ -1853,19 +1836,15 @@ snapshots:
'@vue/devtools-api@6.6.4': {} '@vue/devtools-api@6.6.4': {}
'@vue/language-core@1.8.27(typescript@5.9.3)': '@vue/language-core@3.2.4':
dependencies: dependencies:
'@volar/language-core': 1.11.1 '@volar/language-core': 2.4.27
'@volar/source-map': 1.11.1
'@vue/compiler-dom': 3.5.27 '@vue/compiler-dom': 3.5.27
'@vue/shared': 3.5.27 '@vue/shared': 3.5.27
computeds: 0.0.1 alien-signals: 3.1.2
minimatch: 9.0.5 muggle-string: 0.4.1
muggle-string: 0.3.1
path-browserify: 1.0.1 path-browserify: 1.0.1
vue-template-compiler: 2.7.16 picomatch: 4.0.3
optionalDependencies:
typescript: 5.9.3
'@vue/reactivity@3.5.27': '@vue/reactivity@3.5.27':
dependencies: dependencies:
@ -1923,6 +1902,8 @@ snapshots:
json-schema-traverse: 0.4.1 json-schema-traverse: 0.4.1
uri-js: 4.4.1 uri-js: 4.4.1
alien-signals@3.1.2: {}
ansi-regex@5.0.1: {} ansi-regex@5.0.1: {}
ansi-styles@4.3.0: ansi-styles@4.3.0:
@ -1990,8 +1971,6 @@ snapshots:
dependencies: dependencies:
delayed-stream: 1.0.0 delayed-stream: 1.0.0
computeds@0.0.1: {}
concat-map@0.0.1: {} concat-map@0.0.1: {}
cross-spawn@7.0.6: cross-spawn@7.0.6:
@ -2006,8 +1985,6 @@ snapshots:
dayjs@1.11.19: {} dayjs@1.11.19: {}
de-indent@1.0.2: {}
debug@4.4.3: debug@4.4.3:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@ -2302,8 +2279,6 @@ snapshots:
dependencies: dependencies:
function-bind: 1.1.2 function-bind: 1.1.2
he@1.2.0: {}
ignore@5.3.2: {} ignore@5.3.2: {}
immutable@5.1.4: {} immutable@5.1.4: {}
@ -2398,13 +2373,9 @@ snapshots:
dependencies: dependencies:
brace-expansion: 2.0.2 brace-expansion: 2.0.2
minimatch@9.0.5:
dependencies:
brace-expansion: 2.0.2
ms@2.1.3: {} ms@2.1.3: {}
muggle-string@0.3.1: {} muggle-string@0.4.1: {}
nanoid@3.3.11: {} nanoid@3.3.11: {}
@ -2458,8 +2429,7 @@ snapshots:
picomatch@2.3.1: {} picomatch@2.3.1: {}
picomatch@4.0.3: picomatch@4.0.3: {}
optional: true
pinia-plugin-persistedstate@3.2.3(pinia@2.3.1(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))): pinia-plugin-persistedstate@3.2.3(pinia@2.3.1(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))):
dependencies: dependencies:
@ -2607,6 +2577,8 @@ snapshots:
fsevents: 2.3.3 fsevents: 2.3.3
sass: 1.97.3 sass: 1.97.3
vscode-uri@3.1.0: {}
vue-demi@0.14.10(vue@3.5.27(typescript@5.9.3)): vue-demi@0.14.10(vue@3.5.27(typescript@5.9.3)):
dependencies: dependencies:
vue: 3.5.27(typescript@5.9.3) vue: 3.5.27(typescript@5.9.3)
@ -2629,16 +2601,10 @@ snapshots:
'@vue/devtools-api': 6.6.4 '@vue/devtools-api': 6.6.4
vue: 3.5.27(typescript@5.9.3) vue: 3.5.27(typescript@5.9.3)
vue-template-compiler@2.7.16: vue-tsc@3.2.4(typescript@5.9.3):
dependencies: dependencies:
de-indent: 1.0.2 '@volar/typescript': 2.4.27
he: 1.2.0 '@vue/language-core': 3.2.4
vue-tsc@1.8.27(typescript@5.9.3):
dependencies:
'@volar/typescript': 1.11.1
'@vue/language-core': 1.8.27(typescript@5.9.3)
semver: 7.7.3
typescript: 5.9.3 typescript: 5.9.3
vue@3.5.27(typescript@5.9.3): vue@3.5.27(typescript@5.9.3):

View File

@ -1,4 +1,4 @@
import request from '@/utils/request' import { http } from '@/utils/request'
export interface DashboardStatistics { export interface DashboardStatistics {
customerCount: number customerCount: number
@ -11,8 +11,5 @@ export interface DashboardStatistics {
* *
*/ */
export function getStatistics() { export function getStatistics() {
return request<DashboardStatistics>({ return http.get<DashboardStatistics>('/dashboard/statistics')
url: '/dashboard/statistics',
method: 'get'
})
} }

View File

@ -1,44 +1,30 @@
import request from '@/utils/request' import { http } from '@/utils/request'
import type { SystemConfig } from '@/types' import type { SystemConfig } from '@/types'
/** /**
* *
*/ */
export function getAllConfigs() { export function getAllConfigs() {
return request<SystemConfig[]>({ return http.get<SystemConfig[]>('/system/config')
url: '/system/config',
method: 'get'
})
} }
/** /**
* *
*/ */
export function getConfigValue(configKey: string) { export function getConfigValue(configKey: string) {
return request<string>({ return http.get<string>(`/system/config/value/${configKey}`)
url: `/system/config/value/${configKey}`,
method: 'get'
})
} }
/** /**
* *
*/ */
export function updateConfig(configKey: string, configValue: string) { export function updateConfig(configKey: string, configValue: string) {
return request({ return http.put('/system/config', { configKey, configValue })
url: '/system/config',
method: 'put',
data: { configKey, configValue }
})
} }
/** /**
* *
*/ */
export function batchUpdateConfigs(configs: Record<string, string>) { export function batchUpdateConfigs(configs: Record<string, string>) {
return request({ return http.put('/system/config/batch', configs)
url: '/system/config/batch',
method: 'put',
data: configs
})
} }

View File

@ -54,7 +54,7 @@ const router = createRouter({
}) })
// 路由守卫 // 路由守卫
router.beforeEach((to, from, next) => { router.beforeEach((to, _from, next) => {
const userStore = useUserStore() const userStore = useUserStore()
// 设置页面标题 // 设置页面标题

View File

@ -1,6 +1,6 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { login as loginApi, getUserInfo, logout as logoutApi } from '@/api/auth' import { login as loginApi, getUserInfo } from '@/api/auth'
import type { LoginRequest, User } from '@/types' import type { LoginRequest, User } from '@/types'
export const useUserStore = defineStore( export const useUserStore = defineStore(

View File

@ -168,7 +168,6 @@ const dialogVisible = ref(false)
const dialogTitle = computed(() => (formData.id ? '编辑客户' : '新增客户')) const dialogTitle = computed(() => (formData.id ? '编辑客户' : '新增客户'))
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
const schoolSearchLoading = ref(false) const schoolSearchLoading = ref(false)
const schoolOptions = ref<School[]>([])
const queryForm = reactive({ const queryForm = reactive({
current: 1, current: 1,
@ -339,7 +338,7 @@ const handleDialogClose = () => {
const fetchProtectDays = async () => { const fetchProtectDays = async () => {
try { try {
const res = await getConfigValue('report.protect.days') const res = await getConfigValue('report.protect.days')
protectDays.value = parseInt(res) || 90 protectDays.value = parseInt(res, 10) || 90
} catch (error) { } catch (error) {
console.error('获取配置失败', error) console.error('获取配置失败', error)
} }

View File

@ -181,7 +181,7 @@ const rules: FormRules = {
contactPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }], contactPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
password: [ password: [
{ {
validator: (rule, value, callback) => { validator: (_rule, value, callback) => {
// //
if (value && (value.length < 6 || value.length > 20)) { if (value && (value.length < 6 || value.length > 20)) {
callback(new Error('密码长度必须在6-20位之间')) callback(new Error('密码长度必须在6-20位之间'))
@ -210,7 +210,7 @@ const resetPasswordRules: FormRules = {
confirmPassword: [ confirmPassword: [
{ required: true, message: '请再次输入新密码', trigger: 'blur' }, { required: true, message: '请再次输入新密码', trigger: 'blur' },
{ {
validator: (rule, value, callback) => { validator: (_rule, value, callback) => {
if (value !== resetPasswordForm.newPassword) { if (value !== resetPasswordForm.newPassword) {
callback(new Error('两次输入的密码不一致')) callback(new Error('两次输入的密码不一致'))
} else { } else {

View File

@ -144,7 +144,7 @@ const passwordRules: FormRules = {
confirmPassword: [ confirmPassword: [
{ required: true, message: '请再次输入新密码', trigger: 'blur' }, { required: true, message: '请再次输入新密码', trigger: 'blur' },
{ {
validator: (rule, value, callback) => { validator: (_rule, value, callback) => {
if (value !== passwordForm.newPassword) { if (value !== passwordForm.newPassword) {
callback(new Error('两次输入的密码不一致')) callback(new Error('两次输入的密码不一致'))
} else { } else {

View File

@ -134,7 +134,7 @@
<!-- 审核对话框 --> <!-- 审核对话框 -->
<el-dialog v-model="auditDialogVisible" title="审核报备" width="600px"> <el-dialog v-model="auditDialogVisible" title="审核报备" width="600px">
<el-form ref="auditFormRef" :model="auditForm" label-width="100px"> <el-form :model="auditForm" label-width="100px">
<el-form-item label="审核结果"> <el-form-item label="审核结果">
<el-radio-group v-model="auditForm.approved"> <el-radio-group v-model="auditForm.approved">
<el-radio :label="true">通过</el-radio> <el-radio :label="true">通过</el-radio>
@ -178,7 +178,6 @@ const dialogVisible = ref(false)
const auditDialogVisible = ref(false) const auditDialogVisible = ref(false)
const auditReportId = ref<number>() const auditReportId = ref<number>()
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
const auditFormRef = ref<FormInstance>()
const searchLoading = ref(false) const searchLoading = ref(false)
const customerOptions = ref<Array<{ id: number; name: string }>>([]) const customerOptions = ref<Array<{ id: number; name: string }>>([])

View File

@ -1,8 +1,11 @@
-- 经销商管理系统数据库初始化脚本 -- 经销商管理系统数据库初始化脚本
-- 数据库版本MySQL 8.0 -- 数据库版本MySQL 8.0
CREATE DATABASE IF NOT EXISTS by_crm DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE IF NOT EXISTS crm_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE by_crm; USE crm_db;
SET NAMES utf8mb4;
SET CHARACTER SET utf8mb4;
-- 经销商表 -- 经销商表
CREATE TABLE IF NOT EXISTS crm_dealer ( CREATE TABLE IF NOT EXISTS crm_dealer (
@ -109,7 +112,7 @@ CREATE TABLE IF NOT EXISTS crm_operation_log (
-- 插入默认管理员用户名admin密码Bycrmadmin123BCrypt加密后的值 -- 插入默认管理员用户名admin密码Bycrmadmin123BCrypt加密后的值
INSERT INTO crm_user (username, password, real_name, dealer_id, role, status) VALUES INSERT INTO crm_user (username, password, real_name, dealer_id, role, status) VALUES
('admin', '$10$kWExNPRis.HIzKDa112UZeq8jzGxI2tLFo0zTNRfxhyzk6MzMKPW6', '系统管理员', NULL, 0, 1); ('admin', '$2a$10$kWExNPRis.HIzKDa112UZeq8jzGxI2tLFo0zTNRfxhyzk6MzMKPW6', '系统管理员', NULL, 0, 1);
-- 插入数据字典 -- 插入数据字典
INSERT INTO crm_dict (dict_code, dict_name, description) VALUES INSERT INTO crm_dict (dict_code, dict_name, description) VALUES

2922
sql/02_init_crm_school.sql Normal file

File diff suppressed because it is too large Load Diff