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 @@