From 8057a265ce2e2fd9fdedc278eb5cc3decc79c970 Mon Sep 17 00:00:00 2001 From: ouhaolan Date: Tue, 28 Apr 2026 17:14:57 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E5=85=88=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=B8=80=E7=89=88=E6=9C=AC=E7=9A=84=E7=BB=AD=E4=BF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 12 + .env | 27 ++ .env.local | 36 +++ .env.prod | 39 +++ .env.stage | 33 ++ .env.test | 37 +++ .eslintignore | 8 + .eslintrc-auto-import.json | 259 ++++++++++++++++ .eslintrc.js | 75 +++++ .gitignore | 9 + .prettierignore | 11 + .stylelintignore | 6 + .vscode/extensions.json | 18 ++ .vscode/launch.json | 16 + .vscode/settings.json | 145 +++++++++ ruoyi-vue-pro | 2 +- src/api/car/renewalorder/index.ts | 16 +- .../car/renewalorder/RenewalOrderForm.vue | 51 ++- src/views/car/renewalorder/dashboard.vue | 2 +- src/views/car/renewalorder/index.vue | 93 +++++- 系统功能梳理.md | 291 ++++++++++++++++++ 项目分析报告.md | 4 +- 22 files changed, 1157 insertions(+), 33 deletions(-) create mode 100644 .editorconfig create mode 100644 .env create mode 100644 .env.local create mode 100644 .env.prod create mode 100644 .env.stage create mode 100644 .env.test create mode 100644 .eslintignore create mode 100644 .eslintrc-auto-import.json create mode 100644 .eslintrc.js create mode 100644 .gitignore create mode 100644 .prettierignore create mode 100644 .stylelintignore create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 系统功能梳理.md diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..79a12ff --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true +[*.{js,ts,vue}] +charset = utf-8 # 设置文件字符集为 utf-8 +end_of_line = lf # 控制换行类型(lf | cr | crlf) +insert_final_newline = true # 始终在文件末尾插入一个新行 +indent_style = space # 缩进风格(tab | space) +indent_size = 2 # 缩进大小 +max_line_length = 100 # 最大行长度 + +[*.md] # 仅 md 文件适用以下规则 +max_line_length = off # 关闭最大行长度限制 +trim_trailing_whitespace = false # 关闭末尾空格修剪 diff --git a/.env b/.env new file mode 100644 index 0000000..be4bb3c --- /dev/null +++ b/.env @@ -0,0 +1,27 @@ +# 标题 +VITE_APP_TITLE=途安伴旅后台管理 + +# 项目本地运行端口号 +VITE_PORT=80 + +# open 运行 npm run dev 时自动打开浏览器 +VITE_OPEN=true + +# 租户开关 +VITE_APP_TENANT_ENABLE=true + +# 验证码的开关 +VITE_APP_CAPTCHA_ENABLE=true + +# 文档地址的开关 +VITE_APP_DOCALERT_ENABLE=false + +# 百度统计 +VITE_APP_BAIDU_CODE = a1ff8825baa73c3a78eb96aa40325abc + +# 默认账户密码 +VITE_APP_DEFAULT_LOGIN_TENANT = 途安伴旅 +VITE_APP_DEFAULT_LOGIN_USERNAME = +VITE_APP_DEFAULT_LOGIN_PASSWORD = +#VITE_APP_DEFAULT_LOGIN_USERNAME = admin +#VITE_APP_DEFAULT_LOGIN_PASSWORD = admin123 diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..1275647 --- /dev/null +++ b/.env.local @@ -0,0 +1,36 @@ +# 本地开发环境:本地启动所有项目(前端、后端、APP)时使用,不依赖外部环境 +NODE_ENV=development + +VITE_DEV=true + +# 请求路径 + +#VITE_BASE_URL='http://localhost:48080' +VITE_BASE_URL='https://api.tuanbanlv.com' + +# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务 +VITE_UPLOAD_TYPE=client + +# 上传路径 +VITE_UPLOAD_URL='https://api.tuanbanlv.com/admin-api/infra/file/upload' + +# 接口地址 +VITE_API_URL=/admin-api + +# 是否删除debugger +VITE_DROP_DEBUGGER=false + +# 是否删除console.log +VITE_DROP_CONSOLE=false + +# 是否sourcemap +VITE_SOURCEMAP=false + +# 打包路径 +VITE_BASE_PATH=/ + +# 商城H5会员端域名 +VITE_MALL_H5_DOMAIN='http://localhost:3000' + +# 验证码的开关 +VITE_APP_CAPTCHA_ENABLE=true diff --git a/.env.prod b/.env.prod new file mode 100644 index 0000000..1c0cf86 --- /dev/null +++ b/.env.prod @@ -0,0 +1,39 @@ +# 生产环境:只在打包时使用 +NODE_ENV=production + +VITE_DEV=false + +# 请求路径 +VITE_BASE_URL='https://api.tuanbanlv.com' +#VITE_BASE_URL='https://zmingzhikeji.cn' + +# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 +VITE_UPLOAD_TYPE=client + +# 上传路径 +VITE_UPLOAD_URL='https://api.tuanbanlv.com/admin-api/infra/file/upload' +#VITE_UPLOAD_URL='https://zmingzhikeji.cn/admin-api/infra/file/upload' + +# 接口地址 +VITE_API_URL=/admin-api + +# 是否删除debugger +VITE_DROP_DEBUGGER=true + +# 是否删除console.log +VITE_DROP_CONSOLE=true + +# 是否sourcemap +VITE_SOURCEMAP=false + +# 打包路径 +VITE_BASE_PATH=/ + +# 输出路径 +VITE_OUT_DIR=dist-prod + +# 商城H5会员端域名 +VITE_MALL_H5_DOMAIN='http://1.14.158.154' + +# 验证码的开关 +VITE_APP_CAPTCHA_ENABLE=true diff --git a/.env.stage b/.env.stage new file mode 100644 index 0000000..f7c521b --- /dev/null +++ b/.env.stage @@ -0,0 +1,33 @@ +# 预发布环境:只在打包时使用 +NODE_ENV=production + +VITE_DEV=false + +# 请求路径 +VITE_BASE_URL='http://api-dashboard.yudao.iocoder.cn' + +# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 +VITE_UPLOAD_TYPE=server +# 上传路径 +VITE_UPLOAD_URL='http://api-dashboard.yudao.iocoder.cn/admin-api/infra/file/upload' + +# 接口地址 +VITE_API_URL=/admin-api + +# 是否删除debugger +VITE_DROP_DEBUGGER=true + +# 是否删除console.log +VITE_DROP_CONSOLE=true + +# 是否sourcemap +VITE_SOURCEMAP=false + +# 打包路径 +VITE_BASE_PATH='http://static-vue3.yudao.iocoder.cn/' + +# 输出路径 +VITE_OUT_DIR=dist-stage + +# 商城H5会员端域名 +VITE_MALL_H5_DOMAIN='http://mall.yudao.iocoder.cn' diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..5135d28 --- /dev/null +++ b/.env.test @@ -0,0 +1,37 @@ +# 生产环境:只在打包时使用 +NODE_ENV=production + +VITE_DEV=false + +# 请求路径 +VITE_BASE_URL='https://test.zmingzhikeji.cn' + +# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 +VITE_UPLOAD_TYPE=client + +# 上传路径 +VITE_UPLOAD_URL='https://test.zmingzhikeji.cn/admin-api/infra/file/upload' + +# 接口地址 +VITE_API_URL=/admin-api + +# 是否删除debugger +VITE_DROP_DEBUGGER=true + +# 是否删除console.log +VITE_DROP_CONSOLE=true + +# 是否sourcemap +VITE_SOURCEMAP=false + +# 打包路径 +VITE_BASE_PATH=/ + +# 输出路径 +VITE_OUT_DIR=dist-test + +# 商城H5会员端域名 +VITE_MALL_H5_DOMAIN='https://zmingzhikeji.cn' + +# 验证码的开关 +VITE_APP_CAPTCHA_ENABLE=true diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..1e85c0f --- /dev/null +++ b/.eslintignore @@ -0,0 +1,8 @@ +/build/ +/config/ +/dist/ +/*.js +/test/unit/coverage/ +/node_modules/* +/dist* +/src/main.ts diff --git a/.eslintrc-auto-import.json b/.eslintrc-auto-import.json new file mode 100644 index 0000000..024c96a --- /dev/null +++ b/.eslintrc-auto-import.json @@ -0,0 +1,259 @@ +{ + "globals": { + "EffectScope": true, + "ElMessage": true, + "ElMessageBox": true, + "ElTag": true, + "asyncComputed": true, + "autoResetRef": true, + "computed": true, + "computedAsync": true, + "computedEager": true, + "computedInject": true, + "computedWithControl": true, + "controlledComputed": true, + "controlledRef": true, + "createApp": true, + "createEventHook": true, + "createGlobalState": true, + "createInjectionState": true, + "createReactiveFn": true, + "createSharedComposable": true, + "createUnrefFn": true, + "customRef": true, + "debouncedRef": true, + "debouncedWatch": true, + "defineAsyncComponent": true, + "defineComponent": true, + "eagerComputed": true, + "effectScope": true, + "extendRef": true, + "getCurrentInstance": true, + "getCurrentScope": true, + "h": true, + "ignorableWatch": true, + "inject": true, + "isDefined": true, + "isProxy": true, + "isReactive": true, + "isReadonly": true, + "isRef": true, + "makeDestructurable": true, + "markRaw": true, + "nextTick": true, + "onActivated": true, + "onBeforeMount": true, + "onBeforeUnmount": true, + "onBeforeUpdate": true, + "onClickOutside": true, + "onDeactivated": true, + "onErrorCaptured": true, + "onKeyStroke": true, + "onLongPress": true, + "onMounted": true, + "onRenderTracked": true, + "onRenderTriggered": true, + "onScopeDispose": true, + "onServerPrefetch": true, + "onStartTyping": true, + "onUnmounted": true, + "onUpdated": true, + "pausableWatch": true, + "provide": true, + "reactify": true, + "reactifyObject": true, + "reactive": true, + "reactiveComputed": true, + "reactiveOmit": true, + "reactivePick": true, + "readonly": true, + "ref": true, + "refAutoReset": true, + "refDebounced": true, + "refDefault": true, + "refThrottled": true, + "refWithControl": true, + "resolveComponent": true, + "resolveRef": true, + "resolveUnref": true, + "shallowReactive": true, + "shallowReadonly": true, + "shallowRef": true, + "syncRef": true, + "syncRefs": true, + "templateRef": true, + "throttledRef": true, + "throttledWatch": true, + "toRaw": true, + "toReactive": true, + "toRef": true, + "toRefs": true, + "triggerRef": true, + "tryOnBeforeMount": true, + "tryOnBeforeUnmount": true, + "tryOnMounted": true, + "tryOnScopeDispose": true, + "tryOnUnmounted": true, + "unref": true, + "unrefElement": true, + "until": true, + "useActiveElement": true, + "useArrayEvery": true, + "useArrayFilter": true, + "useArrayFind": true, + "useArrayFindIndex": true, + "useArrayJoin": true, + "useArrayMap": true, + "useArrayReduce": true, + "useArraySome": true, + "useAsyncQueue": true, + "useAsyncState": true, + "useAttrs": true, + "useBase64": true, + "useBattery": true, + "useBluetooth": true, + "useBreakpoints": true, + "useBroadcastChannel": true, + "useBrowserLocation": true, + "useCached": true, + "useClipboard": true, + "useColorMode": true, + "useConfirmDialog": true, + "useCounter": true, + "useCssModule": true, + "useCssVar": true, + "useCssVars": true, + "useCurrentElement": true, + "useCycleList": true, + "useDark": true, + "useDateFormat": true, + "useDebounce": true, + "useDebounceFn": true, + "useDebouncedRefHistory": true, + "useDeviceMotion": true, + "useDeviceOrientation": true, + "useDevicePixelRatio": true, + "useDevicesList": true, + "useDisplayMedia": true, + "useDocumentVisibility": true, + "useDraggable": true, + "useDropZone": true, + "useElementBounding": true, + "useElementByPoint": true, + "useElementHover": true, + "useElementSize": true, + "useElementVisibility": true, + "useEventBus": true, + "useEventListener": true, + "useEventSource": true, + "useEyeDropper": true, + "useFavicon": true, + "useFetch": true, + "useFileDialog": true, + "useFileSystemAccess": true, + "useFocus": true, + "useFocusWithin": true, + "useFps": true, + "useFullscreen": true, + "useGamepad": true, + "useGeolocation": true, + "useIdle": true, + "useImage": true, + "useInfiniteScroll": true, + "useIntersectionObserver": true, + "useInterval": true, + "useIntervalFn": true, + "useKeyModifier": true, + "useLastChanged": true, + "useLocalStorage": true, + "useMagicKeys": true, + "useManualRefHistory": true, + "useMediaControls": true, + "useMediaQuery": true, + "useMemoize": true, + "useMemory": true, + "useMounted": true, + "useMouse": true, + "useMouseInElement": true, + "useMousePressed": true, + "useMutationObserver": true, + "useNavigatorLanguage": true, + "useNetwork": true, + "useNow": true, + "useObjectUrl": true, + "useOffsetPagination": true, + "useOnline": true, + "usePageLeave": true, + "useParallax": true, + "usePermission": true, + "usePointer": true, + "usePointerSwipe": true, + "usePreferredColorScheme": true, + "usePreferredDark": true, + "usePreferredLanguages": true, + "useRafFn": true, + "useRefHistory": true, + "useResizeObserver": true, + "useRoute": true, + "useRouter": true, + "useScreenOrientation": true, + "useScreenSafeArea": true, + "useScriptTag": true, + "useScroll": true, + "useScrollLock": true, + "useSessionStorage": true, + "useShare": true, + "useSlots": true, + "useSpeechRecognition": true, + "useSpeechSynthesis": true, + "useStepper": true, + "useStorage": true, + "useStorageAsync": true, + "useStyleTag": true, + "useSupported": true, + "useSwipe": true, + "useTemplateRefsList": true, + "useTextDirection": true, + "useTextSelection": true, + "useTextareaAutosize": true, + "useThrottle": true, + "useThrottleFn": true, + "useThrottledRefHistory": true, + "useTimeAgo": true, + "useTimeout": true, + "useTimeoutFn": true, + "useTimeoutPoll": true, + "useTimestamp": true, + "useTitle": true, + "useToggle": true, + "useTransition": true, + "useUrlSearchParams": true, + "useUserMedia": true, + "useVModel": true, + "useVModels": true, + "useVibrate": true, + "useVirtualList": true, + "useWakeLock": true, + "useWebNotification": true, + "useWebSocket": true, + "useWebWorker": true, + "useWebWorkerFn": true, + "useWindowFocus": true, + "useWindowScroll": true, + "useWindowSize": true, + "watch": true, + "watchArray": true, + "watchAtMost": true, + "watchDebounced": true, + "watchEffect": true, + "watchIgnorable": true, + "watchOnce": true, + "watchPausable": true, + "watchPostEffect": true, + "watchSyncEffect": true, + "watchThrottled": true, + "watchTriggerable": true, + "watchWithFilter": true, + "whenever": true + } +} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..b28255c --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,75 @@ +// @ts-check +const { defineConfig } = require('eslint-define-config') +module.exports = defineConfig({ + root: true, + env: { + browser: true, + node: true, + es6: true + }, + parser: 'vue-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser', + ecmaVersion: 2020, + sourceType: 'module', + jsxPragma: 'React', + ecmaFeatures: { + jsx: true + } + }, + extends: [ + 'plugin:vue/vue3-recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier', + 'plugin:prettier/recommended', + '@unocss' + ], + rules: { + 'vue/no-setup-props-destructure': 'off', + 'vue/script-setup-uses-vars': 'error', + 'vue/no-reserved-component-names': 'off', + '@typescript-eslint/ban-ts-ignore': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/no-empty-function': 'off', + 'vue/custom-event-name-casing': 'off', + 'no-use-before-define': 'off', + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-unused-vars': 'off', + 'no-unused-vars': 'off', + 'space-before-function-paren': 'off', + + 'vue/attributes-order': 'off', + 'vue/one-component-per-file': 'off', + 'vue/html-closing-bracket-newline': 'off', + 'vue/max-attributes-per-line': 'off', + 'vue/multiline-html-element-content-newline': 'off', + 'vue/singleline-html-element-content-newline': 'off', + 'vue/attribute-hyphenation': 'off', + 'vue/require-default-prop': 'off', + 'vue/require-explicit-emits': 'off', + 'vue/require-toggle-inside-transition': 'off', + 'vue/html-self-closing': [ + 'error', + { + html: { + void: 'always', + normal: 'never', + component: 'always' + }, + svg: 'always', + math: 'always' + } + ], + 'vue/multi-word-component-names': 'off', + 'vue/no-v-html': 'off', + 'prettier/prettier': 'off', // 芋艿:默认关闭 prettier 的 ESLint 校验,因为我们使用的是 IDE 的 Prettier 插件 + '@unocss/order': 'off', // 芋艿:禁用 unocss 【css】顺序的提示,因为暂时不需要这么严格,警告也有点繁琐 + '@unocss/order-attributify': 'off' // 芋艿:禁用 unocss 【属性】顺序的提示,因为暂时不需要这么严格,警告也有点繁琐 + } +}) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..848638a --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +node_modules +.DS_Store +dist +dist-ssr +/dist* +pnpm-debug +auto-*.d.ts +.idea +.history diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..f68ea86 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +/node_modules/** +/dist/ +/dist* +/public/* +/docs/* +/vite.config.ts +/src/types/env.d.ts +/src/types/auto-components.d.ts +/src/types/auto-imports.d.ts +/docs/**/* +CHANGELOG diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000..aa605b4 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,6 @@ +/dist/* +/public/* +public/* +/dist* +/src/types/env.d.ts +/docs/**/* diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..65288b5 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,18 @@ +{ + "recommendations": [ + "christian-kohler.path-intellisense", + "vscode-icons-team.vscode-icons", + "davidanson.vscode-markdownlint", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "mrmlnc.vscode-less", + "lokalise.i18n-ally", + "redhat.vscode-yaml", + "csstools.postcss", + "mikestead.dotenv", + "eamodio.gitlens", + "antfu.iconify", + "antfu.unocss", + "Vue.volar" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..f43edc0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "msedge", + "request": "launch", + "name": "Launch Edge against localhost", + "url": "http://localhost", + "webRoot": "${workspaceFolder}/src", + "sourceMaps": true + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7d8aed4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,145 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib", + "npm.packageManager": "pnpm", + "editor.tabSize": 2, + "prettier.printWidth": 100, // 超过最大值换行 + "editor.defaultFormatter": "esbenp.prettier-vscode", + "files.eol": "\n", + "search.exclude": { + "**/node_modules": true, + "**/*.log": true, + "**/*.log*": true, + "**/bower_components": true, + "**/dist": true, + "**/elehukouben": true, + "**/.git": true, + "**/.gitignore": true, + "**/.svn": true, + "**/.DS_Store": true, + "**/.idea": true, + "**/.vscode": false, + "**/yarn.lock": true, + "**/tmp": true, + "out": true, + "dist": true, + "node_modules": true, + "CHANGELOG.md": true, + "examples": true, + "res": true, + "screenshots": true, + "yarn-error.log": true, + "**/.yarn": true + }, + "files.exclude": { + "**/.cache": true, + "**/.editorconfig": true, + "**/.eslintcache": true, + "**/bower_components": true, + "**/.idea": true, + "**/tmp": true, + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true + }, + "files.watcherExclude": { + "**/.git/objects/**": true, + "**/.git/subtree-cache/**": true, + "**/.vscode/**": true, + "**/node_modules/**": true, + "**/tmp/**": true, + "**/bower_components/**": true, + "**/dist/**": true, + "**/yarn.lock": true + }, + "stylelint.enable": true, + "stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"], + "path-intellisense.mappings": { + "@/": "${workspaceRoot}/src" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" + }, + "[html]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[css]": { + "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" + }, + "[less]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[scss]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.fixAll.stylelint": "explicit" + }, + "[vue]": { + "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" + }, + "i18n-ally.localesPaths": ["src/locales"], + "i18n-ally.keystyle": "nested", + "i18n-ally.sortKeys": true, + "i18n-ally.namespace": false, + "i18n-ally.enabledParsers": ["ts"], + "i18n-ally.sourceLanguage": "en", + "i18n-ally.displayLanguage": "zh-CN", + "i18n-ally.enabledFrameworks": ["vue", "react"], + "cSpell.words": [ + "brotli", + "browserslist", + "codemirror", + "commitlint", + "cropperjs", + "echart", + "echarts", + "esnext", + "esno", + "iconify", + "INTLIFY", + "lintstagedrc", + "logicflow", + "nprogress", + "pinia", + "pnpm", + "qrcode", + "sider", + "sortablejs", + "stylelint", + "svgs", + "unocss", + "unplugin", + "unref", + "videojs", + "VITE", + "vitejs", + "vueuse", + "wangeditor", + "xingyu", + "yudao", + "zxcvbn" + ], + // 控制相关文件嵌套展示 + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.expand": false, + "explorer.fileNesting.patterns": { + "*.ts": "$(capture).test.ts, $(capture).test.tsx", + "*.tsx": "$(capture).test.ts, $(capture).test.tsx", + "*.env": "$(capture).env.*", + "package.json": "pnpm-lock.yaml,yarn.lock,LICENSE,README*,CHANGELOG*,CNAME,.gitattributes,.eslintrc-auto-import.json,.gitignore,prettier.config.js,stylelint.config.js,commitlint.config.js,.stylelintignore,.prettierignore,.gitpod.yml,.eslintrc.js,.eslintignore" + }, + "terminal.integrated.scrollback": 10000, + "nuxt.isNuxtApp": false +} diff --git a/ruoyi-vue-pro b/ruoyi-vue-pro index 39edcaa..3738553 160000 --- a/ruoyi-vue-pro +++ b/ruoyi-vue-pro @@ -1 +1 @@ -Subproject commit 39edcaadf438f7aa3dd802f7c18b4f34778848ff +Subproject commit 3738553724b5f55beb123e9eb3c186d062fcce03 diff --git a/src/api/car/renewalorder/index.ts b/src/api/car/renewalorder/index.ts index d745ddb..78d511f 100644 --- a/src/api/car/renewalorder/index.ts +++ b/src/api/car/renewalorder/index.ts @@ -1,6 +1,6 @@ import request from '@/config/axios' -// 车辆续保订单 VO +// 车辆订单 VO export interface RenewalOrderVO { id: number // 主键ID carBrand: string // 汽车品牌 @@ -45,34 +45,34 @@ export interface RenewalOrderVO { nameplatePhotoUrl?: string // 车名牌照片 } -// 车辆续保订单 API +// 车辆订单 API export const RenewalOrderApi = { - // 查询车辆续保订单分页 + // 查询车辆订单分页 getRenewalOrderPage: async (params: any) => { return await request.get({ url: `/car/renewal-order/page`, params }) }, - // 查询车辆续保订单详情 + // 查询车辆订单详情 getRenewalOrder: async (id: number) => { return await request.get({ url: `/car/renewal-order/get?id=` + id }) }, - // 新增车辆续保订单 + // 新增车辆订单 createRenewalOrder: async (data: RenewalOrderVO) => { return await request.post({ url: `/car/renewal-order/create`, data }) }, - // 修改车辆续保订单 + // 修改车辆订单 updateRenewalOrder: async (data: RenewalOrderVO) => { return await request.put({ url: `/car/renewal-order/update`, data }) }, - // 删除车辆续保订单 + // 删除车辆订单 deleteRenewalOrder: async (id: number) => { return await request.delete({ url: `/car/renewal-order/delete?id=` + id }) }, - // 导出车辆续保订单 Excel + // 导出车辆订单 Excel exportRenewalOrder: async (params) => { return await request.download({ url: `/car/renewal-order/export-excel`, params }) } diff --git a/src/views/car/renewalorder/RenewalOrderForm.vue b/src/views/car/renewalorder/RenewalOrderForm.vue index a496b82..59b7ead 100644 --- a/src/views/car/renewalorder/RenewalOrderForm.vue +++ b/src/views/car/renewalorder/RenewalOrderForm.vue @@ -262,12 +262,12 @@ - + - + - + @@ -429,7 +429,7 @@ import { Qrcode } from '@/components/Qrcode' import * as FileApi from '@/api/infra/file' import { ElMessageBox } from 'element-plus' -/** 车辆续保订单 表单 */ +/** 车辆订单管理 表单 */ defineOptions({ name: 'RenewalOrderForm' }) const { t } = useI18n() // 国际化 @@ -467,6 +467,8 @@ const productTypeLabel = computed(() => { const showContractComponents = computed(() => { return formData.value.productType === '00' || formData.value.productType === '02' }) +// 产品年限:仅当产品类别为 00、02(与合同一致的规定品类)时展示并校验 +const showOriginalWarrantyYears = computed(() => showContractComponents.value) const formData = ref({ id: undefined, carBrand: undefined, @@ -491,7 +493,7 @@ const formData = ref({ serviceProduct: undefined, productType: undefined, productValidity: undefined, - originalWarrantyYears: '3', + originalWarrantyYears: undefined, originalWarrantyMileage: undefined, productFee: undefined, settlementMethod: '00', @@ -529,7 +531,20 @@ const formRules = reactive({ productFee: [{ required: true, message: '产品费用不能为空', trigger: 'blur' }], settlementMethod: [{ required: true, message: '结算方式不能为空', trigger: 'change' }], inputUser: [{ required: true, message: '录单人不能为空', trigger: 'blur' }], - originalWarrantyYears: [{ required: true, message: '产品年限不能为空', trigger: 'blur' }], + originalWarrantyYears: [ + { + validator: (_rule: any, value: any, callback: (e?: Error) => void) => { + const pt = formData.value.productType + const need = pt === '00' || pt === '02' + if (need && (value == null || String(value).trim() === '')) { + callback(new Error('产品年限不能为空')) + } else { + callback() + } + }, + trigger: 'blur' + } + ], drivingLicenseUrl: [{ required: true, message: '请上传行驶证', trigger: 'change' }], carInvoiceUrls: [{ required: true, @@ -580,6 +595,7 @@ const handleProductChange = async (productId: number) => { formData.value.serviceProduct = undefined formData.value.productType = undefined formData.value.productValidity = undefined + formData.value.originalWarrantyYears = undefined return } try { @@ -592,6 +608,16 @@ const handleProductChange = async (productId: number) => { const p: any = product as any formData.value.productType = p.productType || (p.data && p.data.productType) || '' formData.value.productValidity = product.productContent || '' + const pt = formData.value.productType + const needWarrantyYears = pt === '00' || pt === '02' + if (needWarrantyYears) { + const eff = p.effectiveYear ?? p.data?.effectiveYear + if (eff != null && eff !== '') { + formData.value.originalWarrantyYears = String(eff) + } + } else { + formData.value.originalWarrantyYears = undefined + } } catch (error) { console.error('获取产品详情失败:', error) message.error('获取产品详情失败') @@ -781,19 +807,22 @@ const submitForm = async () => { await formRef.value.validate() formLoading.value = true try { - const data = formData.value as unknown as RenewalOrderVO + const payload = { ...formData.value } as unknown as RenewalOrderVO + if (payload.productType !== '00' && payload.productType !== '02') { + payload.originalWarrantyYears = undefined as any + } if (formType.value === 'create') { - const res = await RenewalOrderApi.createRenewalOrder(data) as any + const res = await RenewalOrderApi.createRenewalOrder(payload) as any const newId = res?.data ?? res if (newId) formData.value.id = newId - if ((data.productType === '00' || data.productType === '02') && newId) { + if ((payload.productType === '00' || payload.productType === '02') && newId) { message.success('订单已创建,请让客户扫码完成签名后自动生成合同') await openOnlineSignForOrder(newId) return } message.success(t('common.createSuccess')) } else { - await RenewalOrderApi.updateRenewalOrder(data) + await RenewalOrderApi.updateRenewalOrder(payload) message.success(t('common.updateSuccess')) } dialogVisible.value = false @@ -882,7 +911,7 @@ const resetForm = () => { serviceProduct: undefined, productType: undefined, productValidity: undefined, - originalWarrantyYears: '3', + originalWarrantyYears: undefined, originalWarrantyMileage: undefined, productFee: undefined, settlementMethod: '00', diff --git a/src/views/car/renewalorder/dashboard.vue b/src/views/car/renewalorder/dashboard.vue index 5894b67..112819e 100644 --- a/src/views/car/renewalorder/dashboard.vue +++ b/src/views/car/renewalorder/dashboard.vue @@ -104,7 +104,7 @@ import StoreAnalysis from './components/StoreAnalysis.vue' import SalesTrendChart from './components/SalesTrendChart.vue' import dayjs from 'dayjs' -/** 车辆续保订单看板 */ +/** 车辆订单管理看板 */ defineOptions({ name: 'RenewalOrderDashboard' }) const loading = ref(true) diff --git a/src/views/car/renewalorder/index.vue b/src/views/car/renewalorder/index.vue index 8284ae2..64f47f8 100644 --- a/src/views/car/renewalorder/index.vue +++ b/src/views/car/renewalorder/index.vue @@ -351,19 +351,19 @@