commit
ac0a5c9b67
1667 changed files with 266543 additions and 0 deletions
@ -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 # 关闭末尾空格修剪 |
|||
@ -0,0 +1,37 @@ |
|||
# 标题 |
|||
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=true |
|||
|
|||
# 百度统计 |
|||
VITE_APP_BAIDU_CODE = a1ff8825baa73c3a78eb96aa40325abc |
|||
|
|||
# 默认账户密码 |
|||
VITE_APP_DEFAULT_LOGIN_TENANT = 芋道源码 |
|||
VITE_APP_DEFAULT_LOGIN_USERNAME = admin |
|||
VITE_APP_DEFAULT_LOGIN_PASSWORD = admin123 |
|||
|
|||
# API 加解密 |
|||
VITE_APP_API_ENCRYPT_ENABLE = true |
|||
VITE_APP_API_ENCRYPT_HEADER = X-Api-Encrypt |
|||
VITE_APP_API_ENCRYPT_ALGORITHM = AES |
|||
VITE_APP_API_ENCRYPT_REQUEST_KEY = 52549111389893486934626385991395 |
|||
VITE_APP_API_ENCRYPT_RESPONSE_KEY = 96103715984234343991809655248883 |
|||
# VITE_APP_API_ENCRYPT_REQUEST_KEY = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCls2rIpnGdYnLFgz1XU13GbNQ5DloyPpvW00FPGjqn5Z6JpK+kDtVlnkhwR87iRrE5Vf2WNqRX6vzbLSgveIQY8e8oqGCb829myjf1MuI+ZzN4ghf/7tEYhZJGPI9AbfxFqBUzm+kR3/HByAI22GLT96WM26QiMK8n3tIP/yiLswIDAQAB |
|||
# VITE_APP_API_ENCRYPT_RESPONSE_KEY = MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOH8IfIFxL/MR9XIg1UDv5z1fGXQI93E8wrU4iPFovL/sEt9uSgSkjyidC2O7N+m7EKtoN6b1u7cEwXSkwf3kfK0jdWLSQaNpX5YshqXCBzbDfugDaxuyYrNA4/tIMs7mzZAk0APuRXB35Dmupou7Yw7TFW/7QhQmGfzeEKULQvnAgMBAAECgYAw8LqlQGyQoPv5p3gRxEMOCfgL0JzD3XBJKztiRd35RDh40Nx1ejgjW4dPioFwGiVWd2W8cAGHLzALdcQT2KDJh+T/tsd4SPmI6uSBBK6Ff2DkO+kFFcuYvfclQQKqxma5CaZOSqhgenacmgTMFeg2eKlY3symV6JlFNu/IKU42QJBAOhxAK/Eq3e61aYQV2JSguhMR3b8NXJJRroRs/QHEanksJtl+M+2qhkC9nQVXBmBkndnkU/l2tYcHfSBlAyFySMCQQD445tgm/J2b6qMQmuUGQAYDN8FIkHjeKmha+l/fv0igWm8NDlBAem91lNDIPBUzHL1X1+pcts5bjmq99YdOnhtAkAg2J8dN3B3idpZDiQbC8fd5bGPmdI/pSUudAP27uzLEjr2qrE/QPPGdwm2m7IZFJtK7kK1hKio6u48t/bg0iL7AkEAuUUs94h+v702Fnym+jJ2CHEkXvz2US8UDs52nWrZYiM1o1y4tfSHm8H8bv8JCAa9GHyriEawfBraILOmllFdLQJAQSRZy4wmlaG48MhVXodB85X+VZ9krGXZ2TLhz7kz9iuToy53l9jTkESt6L5BfBDCVdIwcXLYgK+8KFdHN5W7HQ== |
|||
|
|||
# 百度地图 |
|||
VITE_BAIDU_MAP_KEY = 'efHIw2qmH8RzHPxK0z0rbCgzDVLup9LD' |
|||
@ -0,0 +1,37 @@ |
|||
# 开发环境:本地只启动前端项目,依赖开发环境(后端、APP) |
|||
NODE_ENV=production |
|||
|
|||
VITE_DEV=true |
|||
|
|||
# 请求路径 |
|||
VITE_BASE_URL='http://api-dashboard.yudao.iocoder.cn' |
|||
|
|||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 |
|||
VITE_UPLOAD_TYPE=server |
|||
|
|||
# 接口地址 |
|||
VITE_API_URL=/admin-api |
|||
|
|||
# 是否删除debugger |
|||
VITE_DROP_DEBUGGER=false |
|||
|
|||
# 是否删除console.log |
|||
VITE_DROP_CONSOLE=false |
|||
|
|||
# 是否sourcemap |
|||
VITE_SOURCEMAP=true |
|||
|
|||
# 打包路径 |
|||
VITE_BASE_PATH='http://server.ayaojies.com.cn:48080' |
|||
|
|||
# 输出路径 |
|||
VITE_OUT_DIR=dist |
|||
|
|||
# 商城H5会员端域名 |
|||
VITE_MALL_H5_DOMAIN='http://mall.yudao.iocoder.cn' |
|||
|
|||
# 验证码的开关 |
|||
VITE_APP_CAPTCHA_ENABLE=true |
|||
|
|||
# GoView域名 |
|||
VITE_GOVIEW_URL='http://127.0.0.1:3000' |
|||
@ -0,0 +1,34 @@ |
|||
# 本地开发环境:本地启动所有项目(前端、后端、APP)时使用,不依赖外部环境 |
|||
NODE_ENV=development |
|||
|
|||
VITE_DEV=true |
|||
|
|||
# 请求路径 |
|||
VITE_BASE_URL='http://server.ayaojies.com.cn:48080' |
|||
|
|||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务 |
|||
VITE_UPLOAD_TYPE=server |
|||
|
|||
# 接口地址 |
|||
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=false |
|||
|
|||
# GoView域名 |
|||
VITE_GOVIEW_URL='http://127.0.0.1:3000' |
|||
@ -0,0 +1,34 @@ |
|||
# 生产环境:只在打包时使用 |
|||
NODE_ENV=production |
|||
|
|||
VITE_DEV=false |
|||
|
|||
# 请求路径 |
|||
VITE_BASE_URL='http://server.ayaojies.com.cn:48080' |
|||
|
|||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 |
|||
VITE_UPLOAD_TYPE=server |
|||
|
|||
# 接口地址 |
|||
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://mall.yudao.iocoder.cn' |
|||
|
|||
# GoView域名 |
|||
VITE_GOVIEW_URL='http://127.0.0.1:3000' |
|||
@ -0,0 +1,34 @@ |
|||
# 预发布环境:只在打包时使用 |
|||
NODE_ENV=production |
|||
|
|||
VITE_DEV=false |
|||
|
|||
# 请求路径 |
|||
VITE_BASE_URL='http://server.ayaojies.com.cn:48080' |
|||
|
|||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 |
|||
VITE_UPLOAD_TYPE=server |
|||
|
|||
# 接口地址 |
|||
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' |
|||
|
|||
# GoView域名 |
|||
VITE_GOVIEW_URL='http://127.0.0.1:3000' |
|||
@ -0,0 +1,34 @@ |
|||
# 测试环境:只在打包时使用 |
|||
NODE_ENV=production |
|||
|
|||
VITE_DEV=false |
|||
|
|||
# 请求路径 |
|||
VITE_BASE_URL='http://server.ayaojies.com.cn:48080' |
|||
|
|||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 |
|||
VITE_UPLOAD_TYPE=server |
|||
|
|||
# 接口地址 |
|||
VITE_API_URL=/admin-api |
|||
|
|||
# 是否删除debugger |
|||
VITE_DROP_DEBUGGER=true |
|||
|
|||
# 是否删除console.log |
|||
VITE_DROP_CONSOLE=true |
|||
|
|||
# 是否sourcemap |
|||
VITE_SOURCEMAP=false |
|||
|
|||
# 打包路径 |
|||
VITE_BASE_PATH=/admin-ui-vue3/ |
|||
|
|||
# 输出路径 |
|||
VITE_OUT_DIR=dist-test |
|||
|
|||
# 商城H5会员端域名 |
|||
VITE_MALL_H5_DOMAIN='http://mall.yudao.iocoder.cn' |
|||
|
|||
# GoView域名 |
|||
VITE_GOVIEW_URL='http://127.0.0.1:3000' |
|||
@ -0,0 +1,8 @@ |
|||
/build/ |
|||
/config/ |
|||
/dist/ |
|||
/*.js |
|||
/test/unit/coverage/ |
|||
/node_modules/* |
|||
/dist* |
|||
/src/main.ts |
|||
@ -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 |
|||
} |
|||
} |
|||
@ -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 【属性】顺序的提示,因为暂时不需要这么严格,警告也有点繁琐
|
|||
} |
|||
}) |
|||
@ -0,0 +1,14 @@ |
|||
node_modules |
|||
.DS_Store |
|||
dist |
|||
dist-ssr |
|||
/dist* |
|||
pnpm-debug |
|||
auto-*.d.ts |
|||
.idea |
|||
.history |
|||
.image |
|||
|
|||
build |
|||
public/model |
|||
public/Cesium |
|||
@ -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 |
|||
@ -0,0 +1,6 @@ |
|||
/dist/* |
|||
/public/* |
|||
public/* |
|||
/dist* |
|||
/src/types/env.d.ts |
|||
/docs/**/* |
|||
@ -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" |
|||
] |
|||
} |
|||
@ -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 |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,146 @@ |
|||
{ |
|||
"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": "esbenp.prettier-vscode" |
|||
}, |
|||
"[typescriptreact]": { |
|||
"editor.defaultFormatter": "esbenp.prettier-vscode" |
|||
}, |
|||
"[html]": { |
|||
"editor.defaultFormatter": "esbenp.prettier-vscode" |
|||
}, |
|||
"[css]": { |
|||
"editor.defaultFormatter": "esbenp.prettier-vscode" |
|||
}, |
|||
"[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" |
|||
}, |
|||
"editor.formatOnSave": true, |
|||
"[vue]": { |
|||
"editor.defaultFormatter": "Vue.volar" |
|||
}, |
|||
"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 |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
MIT License |
|||
|
|||
Copyright (c) 2021-present Archer |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|||
SOFTWARE. |
|||
@ -0,0 +1,295 @@ |
|||
**严肃声明:现在、未来都不会有商业版本,所有代码全部开源!!** |
|||
|
|||
**「我喜欢写代码,乐此不疲」** |
|||
**「我喜欢做开源,以此为乐」** |
|||
|
|||
我 🐶 在上海艰苦奋斗,早中晚在 top3 大厂认真搬砖,夜里为开源做贡献。 |
|||
|
|||
如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。 |
|||
|
|||
## 🐶 新手必读 |
|||
|
|||
* nodejs > 16.18.0 && pnpm > 8.6.0 (强制使用pnpm) |
|||
* 演示地址【Vue3 + element-plus】:<http://dashboard-vue3.yudao.iocoder.cn> |
|||
* 演示地址【Vue3 + vben5.0(ant-design-vue)】:<http://dashboard-vben.yudao.iocoder.cn> |
|||
* 演示地址【Vue2 + element-ui】:<http://dashboard.yudao.iocoder.cn> |
|||
* 启动文档:<https://doc.iocoder.cn/quick-start/> |
|||
* 视频教程:<https://doc.iocoder.cn/video/> |
|||
|
|||
## 🐯 平台简介 |
|||
|
|||
**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。 |
|||
|
|||
* 采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) 实现 |
|||
* 改换 saas,自动引入等功能 |
|||
* 使用 Element Plus 免费开源的中后台模版,具备如下特性: |
|||
|
|||
 |
|||
|
|||
* **最新技术栈**:使用 Vue3、Vite4 等前端前沿技术开发 |
|||
* **TypeScript**: 应用程序级 JavaScript 的语言 |
|||
* **主题**: 可配置的主题 |
|||
* **国际化**:内置完善的国际化方案 |
|||
* **权限**:内置完善的动态路由权限生成方案 |
|||
* **组件**:二次封装了多个常用的组件 |
|||
* **示例**:内置丰富的示例 |
|||
|
|||
## 技术栈 |
|||
|
|||
| 框架 | 说明 | 版本 | |
|||
|----------------------------------------------------------------------|------------------|--------| |
|||
| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.3.8 | |
|||
| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.5.0 | |
|||
| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.4.2 | |
|||
| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 5.2.2 | |
|||
| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.1.7 | |
|||
| [vueuse](https://vueuse.org/) | 常用工具集 | 10.6.1 | |
|||
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.6.5 | |
|||
| [vue-router](https://router.vuejs.org/) | Vue 路由 | 4.2.5 | |
|||
| [unocss](https://uno.antfu.me/) | 原子 css | 0.57.4 | |
|||
| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 3.1.1 | |
|||
| [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.23 | |
|||
|
|||
## 开发工具 |
|||
|
|||
推荐 VS Code 开发,配合插件如下: |
|||
|
|||
| 插件名 | 功能 | |
|||
|-------------------------------|---------------------| |
|||
| Vue - Official | Vue 与 TypeScript 支持 | |
|||
| unocss | unocss for vscode | |
|||
| Iconify IntelliSense | Iconify 预览和搜索 | |
|||
| i18n Ally | 国际化智能提示 | |
|||
| Stylelint | Css 格式化 | |
|||
| Prettier | 代码格式化 | |
|||
| ESLint | 脚本代码检查 | |
|||
| DotENV | env 文件高亮 | |
|||
|
|||
## 🔥 后端架构 |
|||
|
|||
支持 Spring Boot、Spring Cloud 两种架构: |
|||
|
|||
① Spring Boot 单体架构:<https://doc.iocoder.cn> |
|||
|
|||
 |
|||
|
|||
② Spring Cloud 微服务架构:<https://cloud.iocoder.cn> |
|||
|
|||
 |
|||
|
|||
## 内置功能 |
|||
|
|||
系统内置多种多种业务功能,可以用于快速你的业务系统: |
|||
|
|||
系统内置多种多种业务功能,可以用于快速你的业务系统: |
|||
|
|||
 |
|||
|
|||
* 通用模块(必选):系统功能、基础设施 |
|||
* 通用模块(可选):工作流程、支付系统、数据报表、会员中心 |
|||
* 业务系统(按需):ERP 系统、CRM 系统、商城系统、微信公众号、AI 大模型 |
|||
|
|||
### 系统功能 |
|||
|
|||
| | 功能 | 描述 | |
|||
|-----|-------|---------------------------------| |
|||
| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 | |
|||
| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 | |
|||
| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | |
|||
| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 | |
|||
| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 | |
|||
| | 岗位管理 | 配置系统用户所属担任职务 | |
|||
| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 | |
|||
| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 | |
|||
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | |
|||
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 | |
|||
| 🚀 | 邮件管理 | 邮箱账号、邮件模版、邮件发送日志,支持所有邮件平台 | |
|||
| 🚀 | 站内信 | 系统内的消息通知,提供站内信模版、站内信消息 | |
|||
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 | |
|||
| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 | |
|||
| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 | |
|||
| | 通知公告 | 系统通知公告信息发布维护 | |
|||
| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 | |
|||
| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 | |
|||
| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 | |
|||
|
|||
 |
|||
|
|||
### 工作流程 |
|||
|
|||
 |
|||
|
|||
基于 Flowable 构建,可支持信创(国产)数据库,满足中国特色流程操作: |
|||
|
|||
| BPMN 设计器 | 钉钉/飞书设计器 | |
|||
|-----------------------------|-------------------------------| |
|||
|  |  | |
|||
|
|||
> 历经头部企业生产验证,工作流引擎须标配仿钉钉/飞书 + BPMN 双设计器!!! |
|||
> |
|||
> 前者支持轻量配置简单流程,后者实现复杂场景深度编排 |
|||
|
|||
| 功能列表 | 功能描述 | 是否完成 | |
|||
|------------|-------------------------------------------------------------------------------------|------| |
|||
| SIMPLE 设计器 | 仿钉钉/飞书设计器,支持拖拽搭建表单流程,10 分钟快速完成审批流程配置 | ✅ | |
|||
| BPMN 设计器 | 基于 BPMN 标准开发,适配复杂业务场景,满足多层级审批及流程自动化需求 | ✅ | |
|||
| 会签 | 同一个审批节点设置多个人(如 A、B、C 三人,三人会同时收到待办任务),需全部同意之后,审批才可到下一审批节点 | ✅ | |
|||
| 或签 | 同一个审批节点设置多个人,任意一个人处理后,就能进入下一个节点 | ✅ | |
|||
| 依次审批 | (顺序会签)同一个审批节点设置多个人(如 A、B、C 三人),三人按顺序依次收到待办,即 A 先审批,A 提交后 B 才能审批,需全部同意之后,审批才可到下一审批节点 | ✅ | |
|||
| 抄送 | 将审批结果通知给抄送人,同一个审批默认排重,不重复抄送给同一人 | ✅ | |
|||
| 驳回 | (退回)将审批重置发送给某节点,重新审批。可驳回至发起人、上一节点、任意节点 | ✅ | |
|||
| 转办 | A 转给其 B 审批,B 审批后,进入下一节点 | ✅ | |
|||
| 委派 | A 转给其 B 审批,B 审批后,转给 A,A 继续审批后进入下一节点 | ✅ | |
|||
| 加签 | 允许当前审批人根据需要,自行增加当前节点的审批人,支持向前、向后加签 | ✅ | |
|||
| 减签 | (取消加签)在当前审批人操作之前,减少审批人 | ✅ | |
|||
| 撤销 | (取消流程)流程发起人,可以对流程进行撤销处理 | ✅ | |
|||
| 终止 | 系统管理员,在任意节点终止流程实例 | ✅ | |
|||
| 表单权限 | 支持拖拉拽配置表单,每个审批节点可配置只读、编辑、隐藏权限 | ✅ | |
|||
| 超时审批 | 配置超时审批时间,超时后自动触发审批通过、不通过、驳回等操作 | ✅ | |
|||
| 自动提醒 | 配置提醒时间,到达时间后自动触发短信、邮箱、站内信等通知提醒,支持自定义重复提醒频次 | ✅ | |
|||
| 父子流程 | 主流程设置子流程节点,子流程节点会自动触发子流程。子流程结束后,主流程才会执行(继续往下下执行),支持同步子流程、异步子流程 | ✅ | |
|||
| 条件分支 | (排它分支)用于在流程中实现决策,即根据条件选择一个分支执行 | ✅ | |
|||
| 并行分支 | 允许将流程分成多条分支,不进行条件判断,所有分支都会执行 | ✅ | |
|||
| 包容分支 | (条件分支 + 并行分支的结合体)允许基于条件选择多条分支执行,但如果没有任何一个分支满足条件,则可以选择默认分支 | ✅ | |
|||
| 路由分支 | 根据条件选择一个分支执行(重定向到指定配置节点),也可以选择默认分支执行(继续往下执行) | ✅ | |
|||
| 触发节点 | 执行到该节点,触发 HTTP 请求、HTTP 回调、更新数据、删除数据等 | ✅ | |
|||
| 延迟节点 | 执行到该节点,审批等待一段时间再执行,支持固定时长、固定日期等 | ✅ | |
|||
| 拓展设置 | 流程前置/后置通知,节点(任务)前置、后置通知,流程报表,自动审批去重,自定流程编号、标题、摘要,流程报表等 | ✅ | |
|||
|
|||
### 支付系统 |
|||
|
|||
| | 功能 | 描述 | |
|||
|-----|------|---------------------------| |
|||
| 🚀 | 应用信息 | 配置商户的应用信息,对接支付宝、微信等多个支付渠道 | |
|||
| 🚀 | 支付订单 | 查看用户发起的支付宝、微信等的【支付】订单 | |
|||
| 🚀 | 退款订单 | 查看用户发起的支付宝、微信等的【退款】订单 | |
|||
| 🚀 | 回调通知 | 查看支付回调业务的【支付】【退款】的通知结果 | |
|||
| 🚀 | 接入示例 | 提供接入支付系统的【支付】【退款】的功能实战 | |
|||
|
|||
### 基础设施 |
|||
|
|||
| | 功能 | 描述 | |
|||
|-----|-----------|----------------------------------------------| |
|||
| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 | |
|||
| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 | |
|||
| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 | |
|||
| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 | |
|||
| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 | |
|||
| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 | |
|||
| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 | |
|||
| 🚀 | WebSocket | 提供 WebSocket 接入示例,支持一对一、一对多发送方式 | |
|||
| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 | |
|||
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 | |
|||
| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 | |
|||
| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 | |
|||
| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 | |
|||
| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 | |
|||
| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 | |
|||
| 🚀 | 服务保障 | 基于 Redis 实现分布式锁、幂等、限流功能,满足高并发场景 | |
|||
| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 | |
|||
| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 | |
|||
|
|||
 |
|||
|
|||
### 数据报表 |
|||
|
|||
| | 功能 | 描述 | |
|||
|-----|-------|--------------------| |
|||
| 🚀 | 报表设计器 | 支持数据报表、图形报表、打印设计等 | |
|||
| 🚀 | 大屏设计器 | 拖拽生成数据大屏,内置几十种图表组件 | |
|||
|
|||
### 微信公众号 |
|||
|
|||
| | 功能 | 描述 | |
|||
|----|--------|-------------------------------| |
|||
| 🚀 | 账号管理 | 配置接入的微信公众号,可支持多个公众号 | |
|||
| 🚀 | 数据统计 | 统计公众号的用户增减、累计用户、消息概况、接口分析等数据 | |
|||
| 🚀 | 粉丝管理 | 查看已关注、取关的粉丝列表,可对粉丝进行同步、打标签等操作 | |
|||
| 🚀 | 消息管理 | 查看粉丝发送的消息列表,可主动回复粉丝消息 | |
|||
| 🚀 | 模版消息 | 配置和发送模版消息,用于向粉丝推送通知类消息 | |
|||
| 🚀 | 自动回复 | 自动回复粉丝发送的消息,支持关注回复、消息回复、关键字回复 | |
|||
| 🚀 | 标签管理 | 对公众号的标签进行创建、查询、修改、删除等操作 | |
|||
| 🚀 | 菜单管理 | 自定义公众号的菜单,也可以从公众号同步菜单 | |
|||
| 🚀 | 素材管理 | 管理公众号的图片、语音、视频等素材,支持在线播放语音、视频 | |
|||
| 🚀 | 图文草稿箱 | 新增常用的图文素材到草稿箱,可发布到公众号 | |
|||
| 🚀 | 图文发表记录 | 查看已发布成功的图文素材,支持删除操作 | |
|||
|
|||
### 商城系统 |
|||
|
|||
演示地址:<https://doc.iocoder.cn/mall-preview/> |
|||
|
|||
 |
|||
|
|||
 |
|||
|
|||
### ERP 系统 |
|||
|
|||
演示地址:<https://doc.iocoder.cn/erp-preview/> |
|||
|
|||
 |
|||
|
|||
### CRM 系统 |
|||
|
|||
演示地址:<https://doc.iocoder.cn/crm-preview/> |
|||
|
|||
 |
|||
|
|||
### AI 大模型 |
|||
|
|||
演示地址:<https://doc.iocoder.cn/ai-preview/> |
|||
|
|||
 |
|||
|
|||
 |
|||
|
|||
## 🐷 演示图 |
|||
|
|||
### 系统功能 |
|||
|
|||
| 模块 | biu | biu | biu | |
|||
|----------|-----------------------------|---------------------------|--------------------------| |
|||
| 登录 & 首页 |  |  |  | |
|||
| 用户 & 应用 |  |  |  | |
|||
| 租户 & 套餐 |  |  | - | |
|||
| 部门 & 岗位 |  |  | - | |
|||
| 菜单 & 角色 |  |  | - | |
|||
| 审计日志 |  |  | - | |
|||
| 短信 |  |  |  | |
|||
| 字典 & 敏感词 |  |  |  | |
|||
| 错误码 & 通知 |  |  | - | |
|||
|
|||
### 工作流程 |
|||
|
|||
| 模块 | biu | biu | biu | |
|||
|---------|---------------------------------|---------------------------------|---------------------------------| |
|||
| 流程模型 |  |  |  | |
|||
| 表单 & 分组 |  |  | - | |
|||
| 我的流程 |  |  |  | |
|||
| 待办 & 已办 |  |  |  | |
|||
| OA 请假 |  |  |  | |
|||
|
|||
### 基础设施 |
|||
|
|||
| 模块 | biu | biu | biu | |
|||
|---------------|-------------------------------|-----------------------------|---------------------------| |
|||
| 代码生成 |  |  | - | |
|||
| 文档 |  |  | - | |
|||
| 文件 & 配置 |  |  |  | |
|||
| 定时任务 |  |  | - | |
|||
| API 日志 |  |  | - | |
|||
| MySQL & Redis |  |  | - | |
|||
| 监控平台 |  |  |  | |
|||
|
|||
### 支付系统 |
|||
|
|||
| 模块 | biu | biu | biu | |
|||
|---------|---------------------------|---------------------------------|---------------------------------| |
|||
| 商家 & 应用 |  |  |  | |
|||
| 支付 & 退款 |  |  | --- | |
|||
|
|||
### 数据报表 |
|||
|
|||
| 模块 | biu | biu | biu | |
|||
|-------|---------------------------------|---------------------------------|---------------------------------------| |
|||
| 报表设计器 |  |  |  | |
|||
| 大屏设计器 |  |  |  | |
|||
@ -0,0 +1,156 @@ |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<link rel="icon" href="/favicon.ico" /> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|||
<meta |
|||
name="keywords" |
|||
content="芋道管理系统 基于 vue3 + CompositionAPI + typescript + vite3 + element plus 的后台开源免费管理系统!" |
|||
/> |
|||
<meta |
|||
name="description" |
|||
content="芋道管理系统 基于 vue3 + CompositionAPI + typescript + vite3 + element plus 的后台开源免费管理系统!" |
|||
/> |
|||
<title>%VITE_APP_TITLE%</title> |
|||
<link rel="stylesheet" href="/Cesium/Widgets/widgets.css" /> |
|||
</head> |
|||
<body> |
|||
<div id="app"> |
|||
<style> |
|||
.app-loading { |
|||
display: flex; |
|||
width: 100%; |
|||
height: 100%; |
|||
justify-content: center; |
|||
align-items: center; |
|||
flex-direction: column; |
|||
background: #f0f2f5; |
|||
} |
|||
|
|||
.app-loading .app-loading-wrap { |
|||
position: absolute; |
|||
top: 50%; |
|||
left: 50%; |
|||
display: flex; |
|||
-webkit-transform: translate3d(-50%, -50%, 0); |
|||
transform: translate3d(-50%, -50%, 0); |
|||
justify-content: center; |
|||
align-items: center; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.app-loading .app-loading-title { |
|||
margin-bottom: 30px; |
|||
font-size: 20px; |
|||
font-weight: bold; |
|||
text-align: center; |
|||
} |
|||
|
|||
.app-loading .app-loading-logo { |
|||
width: 100px; |
|||
margin: 0 auto 15px auto; |
|||
} |
|||
|
|||
.app-loading .app-loading-item { |
|||
position: relative; |
|||
display: inline-block; |
|||
width: 60px; |
|||
height: 60px; |
|||
vertical-align: middle; |
|||
border-radius: 50%; |
|||
} |
|||
|
|||
.app-loading .app-loading-outter { |
|||
position: absolute; |
|||
width: 100%; |
|||
height: 100%; |
|||
border: 4px solid #2d8cf0; |
|||
border-bottom: 0; |
|||
border-left-color: transparent; |
|||
border-radius: 50%; |
|||
animation: loader-outter 1s cubic-bezier(0.42, 0.61, 0.58, 0.41) infinite; |
|||
} |
|||
|
|||
.app-loading .app-loading-inner { |
|||
position: absolute; |
|||
top: calc(50% - 20px); |
|||
left: calc(50% - 20px); |
|||
width: 40px; |
|||
height: 40px; |
|||
border: 4px solid #87bdff; |
|||
border-right: 0; |
|||
border-top-color: transparent; |
|||
border-radius: 50%; |
|||
animation: loader-inner 1s cubic-bezier(0.42, 0.61, 0.58, 0.41) infinite; |
|||
} |
|||
|
|||
@-webkit-keyframes loader-outter { |
|||
0% { |
|||
-webkit-transform: rotate(0deg); |
|||
transform: rotate(0deg); |
|||
} |
|||
|
|||
100% { |
|||
-webkit-transform: rotate(360deg); |
|||
transform: rotate(360deg); |
|||
} |
|||
} |
|||
|
|||
@keyframes loader-outter { |
|||
0% { |
|||
-webkit-transform: rotate(0deg); |
|||
transform: rotate(0deg); |
|||
} |
|||
|
|||
100% { |
|||
-webkit-transform: rotate(360deg); |
|||
transform: rotate(360deg); |
|||
} |
|||
} |
|||
|
|||
@-webkit-keyframes loader-inner { |
|||
0% { |
|||
-webkit-transform: rotate(0deg); |
|||
transform: rotate(0deg); |
|||
} |
|||
|
|||
100% { |
|||
-webkit-transform: rotate(-360deg); |
|||
transform: rotate(-360deg); |
|||
} |
|||
} |
|||
|
|||
@keyframes loader-inner { |
|||
0% { |
|||
-webkit-transform: rotate(0deg); |
|||
transform: rotate(0deg); |
|||
} |
|||
|
|||
100% { |
|||
-webkit-transform: rotate(-360deg); |
|||
transform: rotate(-360deg); |
|||
} |
|||
} |
|||
</style> |
|||
<div class="app-loading"> |
|||
<div class="app-loading-wrap"> |
|||
<div class="app-loading-title"> |
|||
<img src="/logo.gif" class="app-loading-logo" alt="Logo" /> |
|||
<div class="app-loading-title">%VITE_APP_TITLE%</div> |
|||
</div> |
|||
<div class="app-loading-item"> |
|||
<div class="app-loading-outter"></div> |
|||
<div class="app-loading-inner"></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<script src="/Cesium/Cesium.js"></script> |
|||
<script> |
|||
window.CESIUM_BASE_URL = '/Cesium/' |
|||
</script> |
|||
<script type="module" src="/src/main.ts"></script> |
|||
</body> |
|||
</html> |
|||
File diff suppressed because it is too large
@ -0,0 +1,164 @@ |
|||
{ |
|||
"name": "yudao-ui-admin-vue3", |
|||
"version": "2025.11-snapshot", |
|||
"description": "基于vue3、vite4、element-plus、typesScript", |
|||
"author": "xingyu", |
|||
"private": false, |
|||
"scripts": { |
|||
"i": "pnpm install", |
|||
"dev": "vite --mode env.local", |
|||
"dev-server": "vite --mode dev", |
|||
"ts:check": "vue-tsc --noEmit", |
|||
"build:local": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build", |
|||
"build:dev": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode dev", |
|||
"build:test": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode test", |
|||
"build:stage": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode stage", |
|||
"build:prod": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode prod", |
|||
"serve:dev": "vite preview --mode dev", |
|||
"serve:prod": "vite preview --mode prod", |
|||
"preview": "pnpm build:local && vite preview", |
|||
"clean": "npx rimraf node_modules", |
|||
"clean:cache": "npx rimraf node_modules/.cache", |
|||
"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src", |
|||
"lint:format": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"", |
|||
"lint:style": "stylelint --fix \"./src/**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/", |
|||
"lint:lint-staged": "lint-staged -c " |
|||
}, |
|||
"dependencies": { |
|||
"@element-plus/icons-vue": "2.3.2", |
|||
"@form-create/designer": "^3.2.6", |
|||
"@form-create/element-ui": "^3.2.11", |
|||
"@iconify/iconify": "^3.1.1", |
|||
"@microsoft/fetch-event-source": "^2.0.1", |
|||
"@videojs-player/vue": "^1.0.0", |
|||
"@vueuse/core": "^10.9.0", |
|||
"@wangeditor-next/editor": "^5.6.46", |
|||
"@wangeditor-next/editor-for-vue": "^5.1.14", |
|||
"@wangeditor-next/plugin-mention": "^1.0.16", |
|||
"@zxcvbn-ts/core": "^3.0.4", |
|||
"animate.css": "^4.1.1", |
|||
"axios": "1.9.0", |
|||
"benz-amr-recorder": "^1.1.5", |
|||
"bpmn-js-token-simulation": "^0.36.0", |
|||
"camunda-bpmn-moddle": "^7.0.1", |
|||
"cesium": "1.123", |
|||
"coordtransform": "^2.1.2", |
|||
"cropperjs": "^1.6.1", |
|||
"crypto-js": "^4.2.0", |
|||
"dayjs": "^1.11.19", |
|||
"diagram-js": "^12.8.0", |
|||
"driver.js": "^1.3.1", |
|||
"echarts": "^5.5.0", |
|||
"echarts-wordcloud": "^2.1.0", |
|||
"element-plus": "2.11.1", |
|||
"fast-xml-parser": "^4.3.2", |
|||
"highlight.js": "^11.9.0", |
|||
"jsencrypt": "^3.3.2", |
|||
"jsoneditor": "^10.1.3", |
|||
"leaflet": "^1.9.4", |
|||
"leaflet-image": "^0.4.0", |
|||
"leaflet-rotatedmarker": "^0.2.0", |
|||
"lodash-es": "^4.17.21", |
|||
"markdown-it": "^14.1.0", |
|||
"markmap-common": "^0.16.0", |
|||
"markmap-lib": "^0.16.1", |
|||
"markmap-toolbar": "^0.17.0", |
|||
"markmap-view": "^0.16.0", |
|||
"min-dash": "^4.1.1", |
|||
"mitt": "^3.0.1", |
|||
"nprogress": "^0.2.0", |
|||
"pinia": "^2.1.7", |
|||
"pinia-plugin-persistedstate": "^3.2.1", |
|||
"qrcode": "^1.5.3", |
|||
"qs": "^6.12.0", |
|||
"snabbdom": "^3.6.2", |
|||
"sortablejs": "^1.15.3", |
|||
"steady-xml": "^0.1.0", |
|||
"url": "^0.11.3", |
|||
"video.js": "^7.21.5", |
|||
"vue": "3.5.12", |
|||
"vue-dompurify-html": "^4.1.4", |
|||
"vue-i18n": "9.10.2", |
|||
"vue-router": "4.4.5", |
|||
"vue-types": "^5.1.1", |
|||
"vue3-print-nb": "^0.1.4", |
|||
"vue3-signature": "^0.2.4", |
|||
"vuedraggable": "^4.1.0", |
|||
"web-storage-cache": "^1.1.1", |
|||
"xml-js": "^1.6.11" |
|||
}, |
|||
"devDependencies": { |
|||
"@commitlint/cli": "^19.0.1", |
|||
"@commitlint/config-conventional": "^19.0.0", |
|||
"@iconify/json": "^2.2.187", |
|||
"@intlify/unplugin-vue-i18n": "^2.0.0", |
|||
"@purge-icons/generated": "^0.9.0", |
|||
"@types/jsoneditor": "^9.9.5", |
|||
"@types/lodash-es": "^4.17.12", |
|||
"@types/node": "^20.11.21", |
|||
"@types/nprogress": "^0.2.3", |
|||
"@types/qrcode": "^1.5.5", |
|||
"@types/qs": "^6.9.12", |
|||
"@typescript-eslint/eslint-plugin": "^7.1.0", |
|||
"@typescript-eslint/parser": "^7.1.0", |
|||
"@unocss/eslint-config": "^0.57.4", |
|||
"@unocss/eslint-plugin": "66.1.0-beta.5", |
|||
"@unocss/transformer-variant-group": "^0.58.5", |
|||
"@vitejs/plugin-legacy": "^5.3.1", |
|||
"@vitejs/plugin-vue": "^5.0.4", |
|||
"@vitejs/plugin-vue-jsx": "^3.1.0", |
|||
"autoprefixer": "^10.4.17", |
|||
"bpmn-js": "^17.9.2", |
|||
"bpmn-js-properties-panel": "5.23.0", |
|||
"consola": "^3.2.3", |
|||
"eslint": "^8.57.0", |
|||
"eslint-config-prettier": "^9.1.0", |
|||
"eslint-define-config": "^2.1.0", |
|||
"eslint-plugin-prettier": "^5.1.3", |
|||
"eslint-plugin-vue": "^9.22.0", |
|||
"lint-staged": "^15.2.2", |
|||
"postcss": "^8.4.35", |
|||
"postcss-html": "^1.6.0", |
|||
"postcss-scss": "^4.0.9", |
|||
"prettier": "^3.2.5", |
|||
"prettier-eslint": "^16.3.0", |
|||
"rimraf": "^5.0.5", |
|||
"rollup": "^4.12.0", |
|||
"sass": "^1.69.5", |
|||
"stylelint": "^16.2.1", |
|||
"stylelint-config-html": "^1.1.0", |
|||
"stylelint-config-recommended": "^14.0.0", |
|||
"stylelint-config-standard": "^36.0.0", |
|||
"stylelint-order": "^6.0.4", |
|||
"terser": "^5.28.1", |
|||
"typescript": "5.3.3", |
|||
"unocss": "^0.58.5", |
|||
"unplugin-auto-import": "^0.16.7", |
|||
"unplugin-element-plus": "^0.8.0", |
|||
"unplugin-vue-components": "^0.25.2", |
|||
"vite": "5.1.4", |
|||
"vite-plugin-compression": "^0.5.1", |
|||
"vite-plugin-ejs": "^1.7.0", |
|||
"vite-plugin-eslint": "^1.8.1", |
|||
"vite-plugin-progress": "^0.0.7", |
|||
"vite-plugin-purge-icons": "^0.10.0", |
|||
"vite-plugin-svg-icons-ng": "^1.3.1", |
|||
"vite-plugin-top-level-await": "^1.4.4", |
|||
"vue-eslint-parser": "^9.3.2", |
|||
"vue-tsc": "^1.8.27" |
|||
}, |
|||
"license": "MIT", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git+https://gitee.com/yudaocode/yudao-ui-admin-vue3" |
|||
}, |
|||
"bugs": { |
|||
"url": "https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues" |
|||
}, |
|||
"homepage": "https://gitee.com/yudaocode/yudao-ui-admin-vue3", |
|||
"web-types": "./web-types.json", |
|||
"engines": { |
|||
"node": ">= 16.0.0", |
|||
"pnpm": ">=8.6.0" |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -0,0 +1,5 @@ |
|||
module.exports = { |
|||
plugins: { |
|||
autoprefixer: {} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
module.exports = { |
|||
printWidth: 100, // 每行代码长度(默认80)
|
|||
tabWidth: 2, // 每个tab相当于多少个空格(默认2)ab进行缩进(默认false)
|
|||
useTabs: false, // 是否使用tab
|
|||
semi: false, // 声明结尾使用分号(默认true)
|
|||
vueIndentScriptAndStyle: false, |
|||
singleQuote: true, // 使用单引号(默认false)
|
|||
quoteProps: 'as-needed', |
|||
bracketSpacing: true, // 对象字面量的大括号间使用空格(默认true)
|
|||
trailingComma: 'none', // 多行使用拖尾逗号(默认none)
|
|||
jsxSingleQuote: false, |
|||
// 箭头函数参数括号 默认avoid 可选 avoid| always
|
|||
// avoid 能省略括号的时候就省略 例如x => x
|
|||
// always 总是有括号
|
|||
arrowParens: 'always', |
|||
insertPragma: false, |
|||
requirePragma: false, |
|||
proseWrap: 'never', |
|||
htmlWhitespaceSensitivity: 'strict', |
|||
endOfLine: 'auto', |
|||
rangeStart: 0 |
|||
} |
|||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 943 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
Binary file not shown.
@ -0,0 +1,784 @@ |
|||
<template> |
|||
<PublicMapComponents class="map-base" :defCenter="[38.8417433306111, 118.43845367431642]" :defZoom="12" /> |
|||
|
|||
<div class="base-div"> |
|||
<div class="title-top"> |
|||
<el-row> |
|||
<el-col :span="6"> |
|||
<div class="title-name"> |
|||
<span>曹妃甸港区船舶岸电监管平台</span> |
|||
</div> |
|||
<div style="text-align: center;"> |
|||
<span class="title-data"> |
|||
<span></span> |
|||
<span style="padding: 0 10px">累计用电:{{ totalPower.toFixed(2) }} kWH</span> |
|||
<span></span> |
|||
</span> |
|||
</div> |
|||
|
|||
</el-col> |
|||
<el-col :span="14"> |
|||
<el-row> |
|||
<template v-for="(item, index) in dataTypeList" :key="index"> |
|||
<el-col :span="24 / dataTypeList.length"> |
|||
<div class="show-type-btn" :class="{ 'show-type-btn-active': activeButtonType === item.value }" |
|||
@click="updateButtonType(index + 1)"> |
|||
{{ item.label }} |
|||
</div> |
|||
</el-col> |
|||
</template> |
|||
|
|||
</el-row> |
|||
</el-col> |
|||
<el-col :span="4"> |
|||
<div class="title-time"> |
|||
<!-- <div class="title-time" @click="splitScreen = !splitScreen">--> |
|||
<!-- 日期 不能换行 换行后显示中多空格 --> |
|||
{{ timer.getFullYear() + '-' }}{{ ((timer.getMonth() + 1) > 9 ? (timer.getMonth() + 1) : ('0' + |
|||
(timer.getMonth() + 1))) + '-' }}{{ (timer.getDate() > 9 ? timer.getDate() : ('0' + timer.getDate())) }} |
|||
<!-- 时间 不能换行 换行后显示中多空格 --> |
|||
{{ (timer.getHours() > 9 ? timer.getHours() : ('0' + timer.getHours())) + ':' }}{{ (timer.getMinutes() > 9 ? |
|||
timer.getMinutes() : ('0' + timer.getMinutes())) + ':' }}{{ timer.getSeconds() > 9 ? timer.getSeconds() : |
|||
('0' + timer.getSeconds()) }} |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
|
|||
<div style="margin-top: 20px"> |
|||
<el-row> |
|||
<el-col :span="showData ? 15 : 24" v-if="!splitScreen"> |
|||
<!-- <PublicMapComponents :defCenter="[38.8417433306111, 118.43845367431642]" :defZoom="12" v-if="showData"/>--> |
|||
</el-col> |
|||
|
|||
|
|||
|
|||
|
|||
<el-col :span="showData ? 9 : 16" v-if="splitScreen"> |
|||
<PublicMapComponents mapName="left" :illustration="true" :defCenter="[38.95448645628942, 118.4517351374956]" |
|||
:defZoom="15" v-if="showData" /> |
|||
<PublicMapComponents mapName="left" :illustration="true" :defCenter="[38.95448645628942, 118.4517351374956]" |
|||
:defZoom="15" v-if="!showData" /> |
|||
</el-col> |
|||
<el-col :span="showData ? 6 : 8" v-if="splitScreen"> |
|||
<PublicMapComponents mapName="right" :illustration="false" |
|||
:defCenter="[38.98524127752966, 118.45273520834166]" :defZoom="16" v-if="showData" /> |
|||
<PublicMapComponents mapName="right" :illustration="false" |
|||
:defCenter="[38.98524127752966, 118.45273520834166]" :defZoom="16" v-if="!showData" /> |
|||
</el-col> |
|||
|
|||
|
|||
|
|||
<el-col :span="showData ? 9 : 0"> |
|||
<div class="data-info"> |
|||
<el-scrollbar height="100%"> |
|||
<div v-show="activeButtonType === 1" class="data-card"> |
|||
<el-row> |
|||
<el-col :span="8"> |
|||
<div class="data-card-title">港口岸电使用情况</div> |
|||
</el-col> |
|||
<el-col :span="16"> |
|||
<div class="data-date"> |
|||
<span :class="dataDate == 1 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(1)">日</span> |
|||
<span :class="dataDate == 2 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(2)">周</span> |
|||
<span :class="dataDate == 3 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(3)">月</span> |
|||
<span :class="dataDate == 4 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(4)">年</span> |
|||
<span :class="dataDate == 5 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(5)">全部</span> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row :gutter="10"> |
|||
<el-col :span="24"> |
|||
<div :class="dataType == 1 ? 'data-info-one-using' : 'data-info-one'" @click="dataType = 1"> |
|||
<div class="data-card-content-big">{{ usedDl.toFixed(2) }}</div> |
|||
<div class="data-card-name">累计用电(千瓦时)</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<div :class="dataType == 2 ? 'data-info-one-using' : 'data-info-one'" @click="dataType = 2"> |
|||
<div class="data-card-content">{{ (usedDl / 7936.84).toFixed(2) }}</div> |
|||
<div class="data-card-name">减少燃油(吨)</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<div :class="dataType == 3 ? 'data-info-one-using' : 'data-info-one'" @click="dataType = 3"> |
|||
<div class="data-card-content">{{ (usedDl / 1.4925373).toFixed(2) }}</div> |
|||
<div class="data-card-name">减少二氧化碳排放(千克)</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div :class="dataType == 4 ? 'data-info-one-using' : 'data-info-one'" @click="dataType = 4"> |
|||
<div class="data-card-content">{{ (usedDl / 684.93132534).toFixed(2) }}</div> |
|||
<div class="data-card-name">减少PM2.5排放(千克)</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div :class="dataType == 5 ? 'data-info-one-using' : 'data-info-one'" @click="dataType = 5"> |
|||
<div class="data-card-content">{{ (usedDl / 55.24862549).toFixed(2) }}</div> |
|||
<div class="data-card-name">减少氮氧化物(千克)</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div :class="dataType == 6 ? 'data-info-one-using' : 'data-info-one'" @click="dataType = 6"> |
|||
<div class="data-card-content">{{ (usedDl / 95.238).toFixed(2) }}</div> |
|||
<div class="data-card-name">减少二氧化硫(千克)</div> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
<div v-show="activeButtonType === 2" class="data-card"> |
|||
<el-row> |
|||
<el-col :span="10"> |
|||
<div class="data-card-title" v-if="dataType == 1">港口企业岸电使用</div> |
|||
<div class="data-card-title" v-else-if="dataType == 2">港口企业燃油消耗减少</div> |
|||
<div class="data-card-title" v-else-if="dataType == 3">港口企业二氧化碳排放减少</div> |
|||
<div class="data-card-title" v-else-if="dataType == 4">港口企业PM2.5排放减少</div> |
|||
<div class="data-card-title" v-else-if="dataType == 5">港口企业氮氧化物排放减少</div> |
|||
<div class="data-card-title" v-else-if="dataType == 6">港口企业二氧化硫排放减少</div> |
|||
</el-col> |
|||
<el-col :span="14"> |
|||
<div class="data-date"> |
|||
<span :class="dataDate == 1 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(1)">日</span> |
|||
<span :class="dataDate == 2 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(2)">周</span> |
|||
<span :class="dataDate == 3 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(3)">月</span> |
|||
<span :class="dataDate == 4 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(4)">年</span> |
|||
<span :class="dataDate == 5 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(5)">全部</span> |
|||
<span class="date-button" v-show="showBerth" @click="updateBerth({})">返回</span> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
<div class="data-card-black"> |
|||
<div v-for="(item, index) in dockShowData" :key="index"> |
|||
<div @click="updateBerth(item)"> |
|||
<el-row> |
|||
<el-col class="data-progress-data" :span="6"> |
|||
<div class="data-progress-name">{{ item.name }}</div> |
|||
</el-col> |
|||
<el-col class="data-progress-data" :span="18"> |
|||
<div> |
|||
<el-progress :text-inside="true" :stroke-width="18" :percentage="item.value * 200" |
|||
status="success"> |
|||
<span> |
|||
{{ (usedDl * item.value / (dataType == 1 ? 1 : dataType == 2 ? 7936.84 : dataType == 3 ? |
|||
1.4925373 : dataType == 4 ? 684.93132534 : dataType == 5 ? 55.24862549 : dataType == 6 ? |
|||
95.238 : 1)).toFixed(2) }} |
|||
{{ dataType == 1 ? ' kWH' : dataType == 2 ? ' t' : ' kg' }} |
|||
</span> |
|||
</el-progress> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
</div> |
|||
<div class="data-card-black"> |
|||
<div v-for="(item, index) in usingData" :key="index"> |
|||
<el-row> |
|||
<el-col :span="4"> |
|||
<div class="ship-info-info-green">{{ item.dock }}</div> |
|||
</el-col> |
|||
<el-col :span="5"> |
|||
<div class="ship-info-info-green">{{ item.berth }}</div> |
|||
</el-col> |
|||
<el-col :span="7"> |
|||
<div class="ship-info-info-green">{{ item.name }}</div> |
|||
</el-col> |
|||
<el-col :span="4"> |
|||
<div class="ship-info-info-green">正在用电</div> |
|||
</el-col> |
|||
<el-col :span="4"> |
|||
<div class="ship-info-info-green">{{ item.used }}</div> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div v-show="activeButtonType === 3" class="data-card"> |
|||
<el-row> |
|||
<el-col :span="10"> |
|||
<div class="data-card-title">船舶岸电使用情况</div> |
|||
</el-col> |
|||
<el-col :span="14"> |
|||
<div class="data-date"> |
|||
<span :class="dataDate == 1 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(1)">日</span> |
|||
<span :class="dataDate == 2 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(2)">周</span> |
|||
<span :class="dataDate == 3 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(3)">月</span> |
|||
<span :class="dataDate == 4 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(4)">年</span> |
|||
<span :class="dataDate == 5 ? 'date-button-using' : 'date-button'" |
|||
@click="updateDataDate(5)">全部</span> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row :gutter="10"> |
|||
<el-col :span="8"> |
|||
<div :class="showShipData == 1 ? 'data-info-one-using' : 'data-info-one'" |
|||
@click="showShipData = showShipData == 1 ? 0 : 1"> |
|||
<div class="data-card-content">13</div> |
|||
<div class="data-card-name-big">在泊船舶数量</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div :class="showShipData == 2 ? 'data-info-one-using' : 'data-info-one'" |
|||
@click="showShipData = showShipData == 2 ? 0 : 2"> |
|||
<div class="data-card-content">3</div> |
|||
<div class="data-card-name-big">使用岸电船舶数量</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div :class="showShipData == 3 ? 'data-info-one-using' : 'data-info-one'" |
|||
@click="showShipData = showShipData == 3 ? 0 : 3"> |
|||
<div class="data-card-content">10</div> |
|||
<div class="data-card-name-big">未使用岸电船舶数量</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="24"> |
|||
<div v-if="showShipData != 0" class="ship-info-card"> |
|||
<div class="ship-info"> |
|||
<div class="ship-info-title" @click="showShipData = 0">收起 ↑</div> |
|||
<el-scrollbar height="180px"> |
|||
<div v-for="(item, index) in shipData" :key="index"> |
|||
<div |
|||
v-if="showShipData == 1 || (showShipData == 2 && item.reasonType == 1) || (showShipData == 3 && (item.reasonType == 2 || item.reasonType == 3))"> |
|||
|
|||
<el-popover :title="item.name" placement="left" :width="430"> |
|||
<template #reference> |
|||
<el-row> |
|||
<el-col :span="3"> |
|||
<div |
|||
:class="item.reasonType == 1 ? 'ship-info-green' : item.reasonType == 2 ? 'ship-info-yellow' : 'ship-info-red'"> |
|||
{{ item.name }}</div> |
|||
</el-col> |
|||
<el-col :span="5"> |
|||
<div |
|||
:class="item.reasonType == 1 ? 'ship-info-green' : item.reasonType == 2 ? 'ship-info-yellow' : 'ship-info-red'"> |
|||
{{ item.dock }}</div> |
|||
</el-col> |
|||
<el-col :span="3"> |
|||
<div |
|||
:class="item.reasonType == 1 ? 'ship-info-green' : item.reasonType == 2 ? 'ship-info-yellow' : 'ship-info-red'"> |
|||
{{ item.berth }}</div> |
|||
</el-col> |
|||
<el-col :span="13"> |
|||
<div |
|||
:class="item.reasonType == 1 ? 'ship-info-green' : item.reasonType == 2 ? 'ship-info-yellow' : 'ship-info-red'"> |
|||
{{ item.reason }}</div> |
|||
</el-col> |
|||
</el-row> |
|||
</template> |
|||
<div> |
|||
<div class="ship-info-info-default">船名:{{ item.name }}</div> |
|||
<div |
|||
:class="item.reasonType == 1 ? 'ship-info-info-green' : item.reasonType == 2 ? 'ship-info-info-yellow' : 'ship-info-info-red'"> |
|||
岸电使用情况:{{ item.reason }}</div> |
|||
<div class="ship-info-info-default">船舶信息:{{ item.info }}</div> |
|||
</div> |
|||
</el-popover> |
|||
</div> |
|||
</div> |
|||
</el-scrollbar> |
|||
</div> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
|
|||
<!-- <div class="data-card"> |
|||
<div class="data-card-title" style="text-align: center;">船舶使用岸电情况</div> |
|||
<el-row :gutter="10"> |
|||
<el-col :span="6"> |
|||
<div class="data-info-one" style="cursor: default;"> |
|||
<div class="data-card-content">20</div> |
|||
<div class="data-card-name">岸电设备数量</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="6"> |
|||
<div class="data-info-one" style="cursor: default;"> |
|||
<div class="data-card-content">10</div> |
|||
<div class="data-card-name">在泊船舶数量</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="6"> |
|||
<div class="data-info-one" style="cursor: default;"> |
|||
<div class="data-card-content">3</div> |
|||
<div class="data-card-name">岸电使用船舶数量</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="6"> |
|||
<div class="data-info-one" style="cursor: default;"> |
|||
<div class="data-card-content">1</div> |
|||
<div class="data-card-name">故障/维护岸电设施数量</div> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
</div>--> |
|||
|
|||
</el-scrollbar> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
</div> |
|||
|
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
|
|||
import PublicMapComponents from './components/index.vue' |
|||
|
|||
defineOptions({ name: 'PublicMap' }) |
|||
|
|||
const timer = ref(new Date()) |
|||
const getTime = () => { |
|||
timer.value = new Date() |
|||
setTimeout(() => { |
|||
getTime() |
|||
}, 100) |
|||
} |
|||
const splitScreen = ref(false) |
|||
|
|||
const showData = ref(true) |
|||
const dataDate = ref<number>(1) |
|||
let defaultDlData = ref<number>(835229.91) |
|||
let totalPower = ref<number>(1492774 + defaultDlData.value) |
|||
let usedDl = ref<number>(defaultDlData.value * dataDate.value) |
|||
const buildDlData = () => { |
|||
setTimeout(() => { |
|||
buildDlData() |
|||
}, 5000) |
|||
defaultDlData.value = (defaultDlData.value + Math.random() * 10 + 30) |
|||
totalPower.value = (1492774 + defaultDlData.value * 1) |
|||
usedDl.value = (defaultDlData.value * dataDate.value) |
|||
} |
|||
const updateDataDate = (number: number) => { |
|||
if (number == 5) { |
|||
window.open("http://server.ayaojies.com.cn:801/login", '_blank'); |
|||
} else { |
|||
dataDate.value = number |
|||
usedDl.value = 835229.9 * number |
|||
} |
|||
} |
|||
const dataType = ref<number>(1) |
|||
|
|||
const dataTypeList = ref<{ value: number, label: string }[]>([ |
|||
{ value: 1, label: '港口岸电使用情况' }, |
|||
{ value: 2, label: '港口企业岸电使用' }, |
|||
{ value: 3, label: '船舶岸电使用情况' }, |
|||
]) |
|||
|
|||
const dockData = ref([ |
|||
{ |
|||
index: 1, name: '华能码头', value: 0.278, berth: [ |
|||
{ index: 1, name: '1泊位', value: 0.25 }, |
|||
{ index: 2, name: '2泊位', value: 0.15 }, |
|||
{ index: 3, name: '3泊位', value: 0.1 }, |
|||
{ index: 4, name: '4泊位', value: 0.4 }, |
|||
{ index: 5, name: '5泊位', value: 0.1 }, |
|||
] |
|||
}, |
|||
{ |
|||
index: 2, name: '国投码头', value: 0.495, berth: [ |
|||
{ index: 1, name: '201泊位', value: 0.25 }, |
|||
{ index: 2, name: '202泊位', value: 0.15 }, |
|||
{ index: 3, name: '203泊位', value: 0.1 }, |
|||
{ index: 4, name: '204泊位', value: 0.4 }, |
|||
{ index: 5, name: '205泊位', value: 0.1 }, |
|||
{ index: 1, name: '206泊位', value: 0.25 }, |
|||
{ index: 2, name: '207泊位', value: 0.15 }, |
|||
{ index: 3, name: '208泊位', value: 0.1 }, |
|||
{ index: 4, name: '209泊位', value: 0.4 }, |
|||
{ index: 5, name: '210泊位', value: 0.1 }, |
|||
] |
|||
}, |
|||
{ |
|||
index: 3, name: '华电码头(储运)', value: 0.227, berth: [ |
|||
{ index: 1, name: '806泊位', value: 0.25 }, |
|||
{ index: 2, name: '807泊位', value: 0.15 }, |
|||
{ index: 3, name: '808泊位', value: 0.1 }, |
|||
{ index: 4, name: '809泊位', value: 0.4 }, |
|||
{ index: 5, name: '810泊位', value: 0.1 }, |
|||
] |
|||
} |
|||
]) |
|||
const dockShowData = ref(dockData.value) |
|||
let showBerth = ref(false) |
|||
const updateBerth = (item: any) => { |
|||
if (showBerth.value) { |
|||
showBerth.value = false |
|||
dockShowData.value = dockData.value |
|||
} |
|||
if (!showBerth.value) { |
|||
if (item.berth) { |
|||
showBerth.value = true |
|||
dockShowData.value = item.berth |
|||
} |
|||
} |
|||
} |
|||
|
|||
const usingData = ref([ |
|||
{ index: 1, name: '华元503', dock: '华能码头', berth: '3泊位', used: '2479kWH' }, |
|||
{ index: 1, name: '和泰通10', dock: '华电码头(储运)', berth: '810泊位', used: '2192kWH' }, |
|||
{ index: 1, name: '永宁2', dock: '华电码头(储运)', berth: '808泊位', used: '692kWH' }, |
|||
|
|||
]) |
|||
|
|||
|
|||
const shipData = ref([ |
|||
{ index: 1, name: '华元503', dock: '华能码头', berth: '3泊位', reasonType: 1, reason: '使用岸电21小时45分钟,2479kWH', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 2, name: '信洋新征程', dock: '国投码头', berth: '202#泊位', reasonType: 2, reason: '无受电设备', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 3, name: '华海航2', dock: '华电码头(储运)', berth: '806泊位', reasonType: 2, reason: '船电设施损坏,预计2025-11-30恢复', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 4, name: '东亿603', dock: '国投码头', berth: '205#泊位', reasonType: 2, reason: '电缆长度不匹配', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 5, name: '东成山', dock: '华能码头', berth: '2泊位', reasonType: 2, reason: '岸电用电接口不匹配', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 6, name: '中茂98', dock: '华电码头(储运)', berth: '807泊位', reasonType: 3, reason: '岸电设施维护中', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 7, name: '舜华', dock: '国投码头', berth: '203#泊位', reasonType: 2, reason: '岸电用电接口不匹配', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 8, name: '浙海温州', dock: '华能码头', berth: '5泊位', reasonType: 2, reason: '岸电设施电压/频率不匹配', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 9, name: '浙能2', dock: '华能码头', berth: '1泊位', reasonType: 2, reason: '无受电设备', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 10, name: '华润电力2', dock: '国投码头', berth: '201#泊位', reasonType: 3, reason: '气象因素禁止作业', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 11, name: '和泰通10', dock: '华电码头(储运)', berth: '810泊位', reasonType: 1, reason: '使用岸电17小时45分钟,2192kWH', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 12, name: '永宁2', dock: '华电码头(储运)', berth: '808泊位', reasonType: 1, reason: '使用岸电3小时15分钟,692kWH', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 13, name: '盛达海', dock: '华能码头', berth: '4泊位', reasonType: 3, reason: '岸电设施维护中', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 13, name: '新世纪128', dock: '国投码头', berth: '201#泊位', reasonType: 2, reason: '岸电设施电压/频率不匹配', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 13, name: '太行128', dock: '国投码头', berth: '206#泊位', reasonType: 2, reason: '无受电设备', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 13, name: '东和明16', dock: '国投码头', berth: '208#泊位', reasonType: 2, reason: '岸电设施电压/频率不匹配', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 13, name: '华鲁海1', dock: '华电码头(储运)', berth: '809泊位', reasonType: 2, reason: '拒绝使用岸电', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 13, name: '安永山', dock: '国投码头', berth: '204#泊位', reasonType: 2, reason: '岸电设施电压/频率不匹配', info: { info: '这里可以显示船舶的信息' } }, |
|||
{ index: 13, name: '华盛151', dock: '国投码头', berth: '209#泊位', reasonType: 2, reason: '电缆长度不匹配', info: { info: '这里可以显示船舶的信息' } }, |
|||
]) |
|||
const showShipData = ref<number>(1) |
|||
const activeButtonType = ref<number>(1) |
|||
|
|||
const updateButtonType = (type: number) => { |
|||
activeButtonType.value = type |
|||
// 在这里可以添加其他业务逻辑 |
|||
console.log('切换到按钮类型:', type) |
|||
} |
|||
|
|||
/** 初始化 **/ |
|||
onMounted(() => { |
|||
getTime() |
|||
buildDlData() |
|||
}) |
|||
|
|||
|
|||
</script> |
|||
<style scoped lang="scss"> |
|||
/* .map-base { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
z-index: -999; |
|||
width: 100%; |
|||
height: 100%; |
|||
background-color: rgba(30, 30, 30, 0.7); |
|||
} */ |
|||
|
|||
.map-base:hover { |
|||
z-index: 999; |
|||
} |
|||
|
|||
.base-div { |
|||
height: 100%; |
|||
//background-color: rgba(10, 50, 100, 1); |
|||
padding: 15px; |
|||
|
|||
.title-top { |
|||
position: fixed; |
|||
top: 20px; |
|||
left: 30px; |
|||
right: 30px; |
|||
width: calc(100% - 60px); |
|||
padding: 30px; |
|||
border-radius: 10px; |
|||
background-color: rgba(255, 255, 255, 0.15); |
|||
box-shadow: 0 0 15px rgba(0, 0, 0, 0.3); |
|||
|
|||
.title-time { |
|||
font-size: 20px; |
|||
color: rgba(20, 200, 255, 0.8); |
|||
font-weight: bold; |
|||
text-align: right; |
|||
} |
|||
|
|||
.title-name { |
|||
font-size: 28px; |
|||
color: rgba(20, 200, 255, 1); |
|||
text-align: center; |
|||
font-weight: bold; |
|||
line-height: 30px; |
|||
text-shadow: 0 0 5px rgba(0, 0, 0, 1), 0 0 6px rgba(20, 200, 255, 0.3), 0 0 7px rgba(20, 200, 255, 0.2), 0 0 8px rgba(20, 200, 255, 0.1); |
|||
} |
|||
|
|||
.show-type-btn { |
|||
margin: 5px; |
|||
padding: 8px 12px; |
|||
border: 1px solid rgba(10, 180, 240, 1); |
|||
border-radius: 5px; |
|||
font-size: 14px; |
|||
color: rgba(10, 180, 240, 1); |
|||
text-align: center; |
|||
cursor: pointer; |
|||
transition: all 0.3s ease; |
|||
} |
|||
|
|||
.show-type-btn-active { |
|||
background-color: rgba(10, 180, 240, 1); |
|||
color: rgba(0, 0, 0, 1); |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.show-type-btn:hover { |
|||
background-color: rgba(10, 180, 240, 0.2); |
|||
transform: translateY(-2px); |
|||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); |
|||
} |
|||
|
|||
.show-type-btn-active:hover { |
|||
background-color: rgba(10, 180, 240, 1); |
|||
transform: none; |
|||
box-shadow: none; |
|||
} |
|||
|
|||
.title-data { |
|||
padding: 8px 15px; |
|||
font-size: 20px; |
|||
color: rgba(20, 200, 255, 0.8); |
|||
font-weight: bold; |
|||
text-align: right; |
|||
border-radius: 10px; |
|||
|
|||
&:active { |
|||
box-shadow: 0 0 15px 5px rgba(20, 200, 255, 0.3), 0 0 25px 10px rgba(20, 200, 255, 0.1); |
|||
} |
|||
} |
|||
} |
|||
|
|||
.data-info { |
|||
position: fixed; |
|||
top: 100px; |
|||
right: 0px; |
|||
width: calc(40%); |
|||
padding: 30px; |
|||
border-radius: 10px; |
|||
margin-left: 10px; |
|||
|
|||
.data-card-black { |
|||
margin-top: 15px; |
|||
padding: 10px; |
|||
background-color: rgba(0, 0, 0, 0.15); |
|||
border-radius: 10px; |
|||
} |
|||
|
|||
.data-card { |
|||
margin-top: 15px; |
|||
padding: 10px; |
|||
background-color: rgba(255, 255, 255, 0.15); |
|||
border-radius: 10px; |
|||
|
|||
.data-card-title { |
|||
font-size: 18px; |
|||
color: rgba(10, 180, 240, 1); |
|||
font-weight: bold; |
|||
line-height: 30px; |
|||
text-shadow: 0 0 3px rgba(0, 0, 0, 1), 0 0 4px rgba(20, 200, 255, 0.3), 0 0 5px rgba(20, 200, 255, 0.2), 0 0 6px rgba(20, 200, 255, 0.1); |
|||
} |
|||
|
|||
.data-date { |
|||
text-align: right; |
|||
margin: 2px; |
|||
|
|||
.date-button { |
|||
margin: 6px; |
|||
padding: 4px 8px; |
|||
border: 1px solid rgba(10, 180, 240, 1); |
|||
border-radius: 5px; |
|||
font-size: 12px; |
|||
color: rgba(10, 180, 240, 1); |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.date-button-using { |
|||
margin: 6px; |
|||
padding: 4px 8px; |
|||
background-color: rgba(10, 180, 240, 1); |
|||
border: 1px solid rgba(10, 180, 240, 1); |
|||
border-radius: 5px; |
|||
font-size: 12px; |
|||
color: rgba(0, 0, 0, 1); |
|||
cursor: default; |
|||
} |
|||
} |
|||
|
|||
.data-info-one { |
|||
margin-top: 10px; |
|||
padding: 10px; |
|||
text-align: center; |
|||
background-color: rgba(10, 30, 30, 0.2); |
|||
border: 1px solid rgba(10, 130, 170, 1); |
|||
border-radius: 10px; |
|||
cursor: pointer; |
|||
|
|||
.data-card-content-big { |
|||
font-size: 30px; |
|||
color: rgba(10, 180, 240, 1); |
|||
font-weight: bold; |
|||
line-height: 30px; |
|||
text-shadow: 0 0 3px rgba(0, 0, 0, 1), 0 0 4px rgba(20, 200, 255, 0.3), 0 0 5px rgba(20, 200, 255, 0.2), 0 0 6px rgba(20, 200, 255, 0.1); |
|||
} |
|||
|
|||
.data-card-content { |
|||
font-size: 25px; |
|||
color: rgba(10, 180, 240, 1); |
|||
font-weight: bold; |
|||
line-height: 25px; |
|||
text-shadow: 0 0 3px rgba(0, 0, 0, 1), 0 0 4px rgba(20, 200, 255, 0.3), 0 0 5px rgba(20, 200, 255, 0.2), 0 0 6px rgba(20, 200, 255, 0.1); |
|||
} |
|||
|
|||
.data-card-name { |
|||
margin-top: 5px; |
|||
font-size: 10px; |
|||
color: rgba(200, 200, 200, 1); |
|||
} |
|||
|
|||
.data-card-name-big { |
|||
margin-top: 5px; |
|||
font-size: 16px; |
|||
color: rgba(240, 240, 240, 1); |
|||
} |
|||
} |
|||
|
|||
.data-info-one-using { |
|||
margin-top: 10px; |
|||
padding: 10px; |
|||
text-align: center; |
|||
background-color: rgba(30, 190, 240, 0.2); |
|||
border: 1px solid rgba(50, 200, 255, 1); |
|||
border-radius: 10px; |
|||
cursor: pointer; |
|||
|
|||
.data-card-content-big { |
|||
font-size: 30px; |
|||
color: rgba(10, 180, 240, 1); |
|||
font-weight: bold; |
|||
line-height: 30px; |
|||
text-shadow: 0 0 3px rgba(0, 0, 0, 1), 0 0 4px rgba(20, 200, 255, 0.3), 0 0 5px rgba(20, 200, 255, 0.2), 0 0 6px rgba(20, 200, 255, 0.1); |
|||
} |
|||
|
|||
.data-card-content { |
|||
font-size: 25px; |
|||
color: rgba(10, 180, 240, 1); |
|||
font-weight: bold; |
|||
line-height: 25px; |
|||
text-shadow: 0 0 3px rgba(0, 0, 0, 1), 0 0 4px rgba(20, 200, 255, 0.3), 0 0 5px rgba(20, 200, 255, 0.2), 0 0 6px rgba(20, 200, 255, 0.1); |
|||
} |
|||
|
|||
.data-card-name { |
|||
margin-top: 5px; |
|||
font-size: 10px; |
|||
color: rgba(200, 200, 200, 1); |
|||
} |
|||
|
|||
.data-card-name-big { |
|||
margin-top: 5px; |
|||
font-size: 16px; |
|||
color: rgba(240, 240, 240, 1); |
|||
} |
|||
} |
|||
|
|||
.data-progress-name { |
|||
font-size: 15px; |
|||
color: rgba(10, 180, 240, 1); |
|||
font-weight: bold; |
|||
line-height: 15px; |
|||
text-shadow: 0 0 3px rgba(0, 0, 0, 1), 0 0 4px rgba(20, 200, 255, 0.3), 0 0 5px rgba(20, 200, 255, 0.2), 0 0 6px rgba(20, 200, 255, 0.1); |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.data-progress-data { |
|||
margin-top: 10px; |
|||
margin-bottom: 5px; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.ship-info-card { |
|||
margin-top: 10px; |
|||
font-size: 15px; |
|||
line-height: 30px; |
|||
|
|||
.ship-info-title { |
|||
padding: 10px; |
|||
text-align: center; |
|||
font-size: 15px; |
|||
color: rgba(10, 180, 240, 1); |
|||
font-weight: 400; |
|||
line-height: 15px; |
|||
border: 1px solid rgba(10, 180, 240, 1); |
|||
border-radius: 7px; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.ship-info { |
|||
border-radius: 10px; |
|||
border: 1px solid rgba(10, 180, 240, 1); |
|||
background-color: rgba(10, 30, 30, 0.2); |
|||
|
|||
.ship-info-green { |
|||
margin-left: 10px; |
|||
color: rgba(50, 255, 100, 1); |
|||
} |
|||
|
|||
.ship-info-red { |
|||
margin-left: 10px; |
|||
color: rgba(255, 70, 70, 1); |
|||
} |
|||
|
|||
.ship-info-yellow { |
|||
margin-left: 10px; |
|||
color: rgba(255, 150, 0, 1); |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
.ship-info-info-default { |
|||
margin-left: 10px; |
|||
margin-bottom: 5px; |
|||
color: rgba(50, 50, 50, 1); |
|||
} |
|||
|
|||
.ship-info-info-green { |
|||
margin-left: 10px; |
|||
margin-bottom: 5px; |
|||
color: rgba(50, 200, 80, 1); |
|||
} |
|||
|
|||
.ship-info-info-red { |
|||
margin-left: 10px; |
|||
margin-bottom: 5px; |
|||
color: rgba(255, 70, 70, 1); |
|||
} |
|||
|
|||
.ship-info-info-yellow { |
|||
margin-left: 10px; |
|||
margin-bottom: 5px; |
|||
color: rgba(255, 150, 0, 1); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,182 @@ |
|||
<template> |
|||
<div ref="chartContainer" class="bar-chart-container"></div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue' |
|||
import * as echarts from 'echarts' |
|||
|
|||
// 定义组件属性 |
|||
interface Props { |
|||
chartData?: Array<{ name: string; value: number }> |
|||
title?: string |
|||
color?: string |
|||
} |
|||
|
|||
const props = withDefaults(defineProps<Props>(), { |
|||
chartData: () => [], |
|||
title: '', |
|||
color: '#1296db' |
|||
}) |
|||
|
|||
// 图表容器引用和实例 |
|||
const chartContainer = ref<HTMLDivElement | null>(null) |
|||
let chartInstance: echarts.ECharts | null = null |
|||
|
|||
// 初始化图表 |
|||
const initChart = () => { |
|||
if (chartContainer.value) { |
|||
chartInstance = echarts.init(chartContainer.value) |
|||
updateChart() |
|||
} |
|||
} |
|||
|
|||
// 更新图表 |
|||
const updateChart = () => { |
|||
if (!chartInstance || !props.chartData.length) return |
|||
|
|||
// 按数值从高到低排序 |
|||
const sortedData = [...props.chartData].sort((a, b) => b.value - a.value) |
|||
|
|||
const option = { |
|||
title: { |
|||
// text: props.title, |
|||
textStyle: { |
|||
color: '#fff', |
|||
fontSize: 14 |
|||
}, |
|||
left: 'center' |
|||
}, |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
axisPointer: { |
|||
type: 'shadow' |
|||
}, |
|||
backgroundColor: 'rgba(0, 0, 0, 0.7)', |
|||
borderColor: 'rgba(30, 120, 255, 0.4)', |
|||
borderWidth: 1, |
|||
textStyle: { |
|||
color: '#fff' |
|||
} |
|||
}, |
|||
grid: { |
|||
left: '5%', |
|||
right: '5%', |
|||
top: '5%', |
|||
bottom: '5%', |
|||
containLabel: true |
|||
}, |
|||
xAxis: { |
|||
type: 'category', |
|||
data: sortedData.map(item => item.name), |
|||
axisLine: { |
|||
lineStyle: { |
|||
color: 'rgba(255, 255, 255, 0.3)' |
|||
} |
|||
}, |
|||
axisLabel: { |
|||
color: 'rgba(255, 255, 255, 0.7)', |
|||
rotate: 0, |
|||
interval: 0, |
|||
margin: 15 |
|||
} |
|||
}, |
|||
yAxis: { |
|||
type: 'value', |
|||
show: false, |
|||
axisLine: { |
|||
show: false |
|||
}, |
|||
splitLine: { |
|||
show: false |
|||
}, |
|||
axisLabel: { |
|||
show: false |
|||
} |
|||
}, |
|||
series: [ |
|||
{ |
|||
type: 'bar', |
|||
data: sortedData.map(item => item.value), |
|||
barWidth: '40%', |
|||
itemStyle: { |
|||
color: { |
|||
type: 'linear', |
|||
x: 0, |
|||
y: 0, |
|||
x2: 0, |
|||
y2: 1, |
|||
colorStops: [ |
|||
{ |
|||
offset: 0, |
|||
color: props.color |
|||
}, |
|||
{ |
|||
offset: 1, |
|||
color: props.color + '80' |
|||
} |
|||
] |
|||
}, |
|||
borderRadius: [4, 4, 0, 0] |
|||
}, |
|||
emphasis: { |
|||
itemStyle: { |
|||
color: props.color |
|||
} |
|||
}, |
|||
label: { |
|||
show: true, |
|||
position: 'top', |
|||
color: '#fff', |
|||
formatter: '{c}', |
|||
fontSize: 12, |
|||
overflow: 'truncate', |
|||
width: 80, |
|||
ellipsis: '...' |
|||
} |
|||
} |
|||
] |
|||
} |
|||
|
|||
chartInstance.setOption(option) |
|||
} |
|||
|
|||
// 监听数据变化 |
|||
watch( |
|||
() => props.chartData, |
|||
() => { |
|||
updateChart() |
|||
}, |
|||
{ deep: true } |
|||
) |
|||
|
|||
// 窗口大小改变时重绘图表 |
|||
const handleResize = () => { |
|||
if (chartInstance) { |
|||
chartInstance.resize() |
|||
} |
|||
} |
|||
|
|||
// 组件挂载时初始化图表 |
|||
onMounted(() => { |
|||
initChart() |
|||
window.addEventListener('resize', handleResize) |
|||
}) |
|||
|
|||
// 组件销毁前清理资源 |
|||
onBeforeUnmount(() => { |
|||
window.removeEventListener('resize', handleResize) |
|||
if (chartInstance) { |
|||
chartInstance.dispose() |
|||
chartInstance = null |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.bar-chart-container { |
|||
width: 100%; |
|||
height: 100%; |
|||
min-height: 200px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,165 @@ |
|||
<template> |
|||
<div ref="chartContainer" class="line-chart-container"></div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue' |
|||
import * as echarts from 'echarts' |
|||
|
|||
// 定义组件属性 |
|||
interface Props { |
|||
chartData?: Array<{ name: string; value: number }> |
|||
title?: string |
|||
color?: string |
|||
} |
|||
|
|||
const props = withDefaults(defineProps<Props>(), { |
|||
chartData: () => [], |
|||
title: '', |
|||
color: '#1296db' |
|||
}) |
|||
|
|||
// 图表容器引用和实例 |
|||
const chartContainer = ref<HTMLDivElement | null>(null) |
|||
let chartInstance: echarts.ECharts | null = null |
|||
|
|||
// 初始化图表 |
|||
const initChart = () => { |
|||
if (chartContainer.value) { |
|||
chartInstance = echarts.init(chartContainer.value) |
|||
updateChart() |
|||
} |
|||
} |
|||
|
|||
// 更新图表 |
|||
const updateChart = () => { |
|||
if (!chartInstance || !props.chartData.length) return |
|||
|
|||
const option = { |
|||
title: { |
|||
text: props.title, |
|||
textStyle: { |
|||
color: '#fff', |
|||
fontSize: 14 |
|||
}, |
|||
left: 'center' |
|||
}, |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
backgroundColor: 'rgba(0, 0, 0, 0.7)', |
|||
borderColor: 'rgba(30, 120, 255, 0.4)', |
|||
borderWidth: 1, |
|||
textStyle: { |
|||
color: '#fff' |
|||
} |
|||
}, |
|||
xAxis: { |
|||
type: 'category', |
|||
data: props.chartData.map(item => item.name), |
|||
axisLine: { |
|||
lineStyle: { |
|||
color: 'rgba(255, 255, 255, 0.3)' |
|||
} |
|||
}, |
|||
axisLabel: { |
|||
color: 'rgba(255, 255, 255, 0.7)' |
|||
} |
|||
}, |
|||
yAxis: { |
|||
type: 'value', |
|||
axisLine: { |
|||
lineStyle: { |
|||
color: 'rgba(255, 255, 255, 0.3)' |
|||
} |
|||
}, |
|||
splitLine: { |
|||
lineStyle: { |
|||
color: 'rgba(255, 255, 255, 0.1)' |
|||
} |
|||
}, |
|||
axisLabel: { |
|||
color: 'rgba(255, 255, 255, 0.7)' |
|||
} |
|||
}, |
|||
series: [ |
|||
{ |
|||
data: props.chartData.map(item => item.value), |
|||
type: 'line', |
|||
smooth: true, |
|||
showSymbol: false, |
|||
lineStyle: { |
|||
color: props.color, |
|||
width: 2 |
|||
}, |
|||
areaStyle: { |
|||
color: { |
|||
type: 'linear', |
|||
x: 0, |
|||
y: 0, |
|||
x2: 0, |
|||
y2: 1, |
|||
colorStops: [ |
|||
{ |
|||
offset: 0, |
|||
color: props.color + '80' // 添加透明度 |
|||
}, |
|||
{ |
|||
offset: 1, |
|||
color: props.color + '00' // 透明 |
|||
} |
|||
] |
|||
} |
|||
} |
|||
} |
|||
], |
|||
grid: { |
|||
left: '5%', |
|||
right: '5%', |
|||
top: '15%', |
|||
bottom: '10%', |
|||
containLabel: true |
|||
} |
|||
} |
|||
|
|||
chartInstance.setOption(option) |
|||
} |
|||
|
|||
// 监听数据变化 |
|||
watch( |
|||
() => props.chartData, |
|||
() => { |
|||
updateChart() |
|||
}, |
|||
{ deep: true } |
|||
) |
|||
|
|||
// 窗口大小改变时重绘图表 |
|||
const handleResize = () => { |
|||
if (chartInstance) { |
|||
chartInstance.resize() |
|||
} |
|||
} |
|||
|
|||
// 组件挂载时初始化图表 |
|||
onMounted(() => { |
|||
initChart() |
|||
window.addEventListener('resize', handleResize) |
|||
}) |
|||
|
|||
// 组件销毁前清理资源 |
|||
onBeforeUnmount(() => { |
|||
window.removeEventListener('resize', handleResize) |
|||
if (chartInstance) { |
|||
chartInstance.dispose() |
|||
chartInstance = null |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.line-chart-container { |
|||
width: 100%; |
|||
height: 100%; |
|||
min-height: 200px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,126 @@ |
|||
<template> |
|||
<div ref="chartContainer" class="pie-chart-container"></div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue' |
|||
import * as echarts from 'echarts' |
|||
|
|||
// 定义组件props |
|||
interface Props { |
|||
chartData?: Array<{ name: string; value: number }> |
|||
title?: string |
|||
} |
|||
|
|||
const props = withDefaults(defineProps<Props>(), { |
|||
chartData: () => [], |
|||
title: '' |
|||
}) |
|||
|
|||
const chartContainer = ref<HTMLDivElement | null>(null) |
|||
let chartInstance: echarts.ECharts | null = null |
|||
|
|||
// 初始化图表 |
|||
const initChart = () => { |
|||
if (chartContainer.value) { |
|||
chartInstance = echarts.init(chartContainer.value) |
|||
updateChart() |
|||
} |
|||
} |
|||
|
|||
// 更新图表 |
|||
const updateChart = () => { |
|||
if (!chartInstance || !props.chartData) return |
|||
|
|||
const option = { |
|||
title: { |
|||
// text: props.title, |
|||
left: 'center', |
|||
textStyle: { |
|||
color: '#FFF' |
|||
} |
|||
}, |
|||
tooltip: { |
|||
trigger: 'item' |
|||
}, |
|||
legend: { |
|||
show: true, |
|||
type: 'scroll', // 👈 开启可滚动图例 |
|||
orient: 'vertical', // 👈 垂直排列 |
|||
right: 10, |
|||
top: 'center', |
|||
textStyle: { |
|||
color: '#FFF' |
|||
} |
|||
}, |
|||
series: [ |
|||
{ |
|||
name: props.title, |
|||
type: 'pie', |
|||
radius: ['30%', '50%'], |
|||
center: ['35%', '50%'], // 👈 左移饼图避免与图例重叠 |
|||
avoidLabelOverlap: true, |
|||
itemStyle: { |
|||
borderRadius: 0, |
|||
borderColor: '#fff', |
|||
borderWidth: 1 |
|||
}, |
|||
label: { |
|||
show: true, |
|||
formatter: '{b}\n{d}%', |
|||
fontSize: 10 |
|||
}, |
|||
emphasis: { |
|||
label: { |
|||
show: true, |
|||
fontSize: 14, |
|||
fontWeight: 'bold' |
|||
} |
|||
}, |
|||
labelLine: { |
|||
show: true |
|||
}, |
|||
data: props.chartData |
|||
} |
|||
] |
|||
} |
|||
|
|||
chartInstance.setOption(option, true) |
|||
} |
|||
|
|||
// 窗口大小改变时重置图表大小 |
|||
const handleResize = () => { |
|||
if (chartInstance) { |
|||
chartInstance.resize() |
|||
} |
|||
} |
|||
|
|||
// 监听数据变化 |
|||
watch( |
|||
() => props.chartData, |
|||
() => { |
|||
updateChart() |
|||
}, |
|||
{ deep: true } |
|||
) |
|||
|
|||
// 初始化和销毁 |
|||
onMounted(() => { |
|||
initChart() |
|||
window.addEventListener('resize', handleResize) |
|||
}) |
|||
|
|||
onBeforeUnmount(() => { |
|||
if (chartInstance) { |
|||
chartInstance.dispose() |
|||
} |
|||
window.removeEventListener('resize', handleResize) |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.pie-chart-container { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,679 @@ |
|||
<template> |
|||
<div> |
|||
<div class="parent"> |
|||
<div class="mapParent"> |
|||
<div :id="defaultData.mapName" class="my-map"></div> |
|||
</div> |
|||
<div class="child"> |
|||
<div class="text-title">状态图示</div> |
|||
<div> |
|||
<div class="circle circle-green"></div> |
|||
<div class="text-info text-info-green">正在使用岸电</div> |
|||
</div> |
|||
<div> |
|||
<div class="circle circle-yellow"></div> |
|||
<div class="text-info text-info-yellow">船方原因未使用岸电</div> |
|||
</div> |
|||
<div> |
|||
<div class="circle circle-red"></div> |
|||
<div class="text-info text-info-red">岸方原因未使用岸电</div> |
|||
</div> |
|||
</div> |
|||
<!-- <div class="child" v-if="showButton && usingData.status === 2">--> |
|||
<!-- <el-button class="text-title" style="width:100%;background-color: rgba(255, 255, 255, 0);text-align: center;border: none;" @click="updateStatus">确认该事件</el-button>--> |
|||
<!-- </div>--> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import interface_red from '@/assets/svgs/svg/岸电箱-维护保养.png' |
|||
import interface_yellow from '@/assets/svgs/svg/用电接口-黄色.gif' |
|||
import interface_blue from '@/assets/svgs/svg/岸电箱-正常.png' |
|||
import interface_green from '@/assets/svgs/svg/用电接口-绿色.svg' |
|||
import ship_red from '@/assets/svgs/svg/船-红色.gif' |
|||
import ship_yellow from '@/assets/svgs/svg/船-黄色.svg' |
|||
import ship_blue from '@/assets/svgs/svg/船-蓝色.svg' |
|||
import ship_green from '@/assets/svgs/svg/船-绿色.png' |
|||
import ship_brown from '@/assets/svgs/svg/船-棕色.svg' |
|||
import ship_problem from '@/assets/svgs/svg/船-问号.gif' |
|||
import shorepower_blue from '@/assets/svgs/svg/配电室.png' |
|||
import shorepower_green from '@/assets/svgs/svg/岸电设施-绿色.svg' |
|||
import problem from '@/assets/svgs/svg/问号-棕色.svg' |
|||
import problem_red from '@/assets/svgs/svg/问号-红色.svg' |
|||
|
|||
import L from "leaflet"; |
|||
import "leaflet/dist/leaflet.css"; |
|||
import "leaflet-rotatedmarker"; |
|||
import {MapApi} from "@/api/shorepower/map"; |
|||
import baseInfo from "@/views/shorepower/map/baseMapInfo"; |
|||
|
|||
defineOptions({ name: 'PublicMapComponents' }) |
|||
|
|||
|
|||
// const getShorePowerEquipmentStr = (icon: any) => { |
|||
// return `<div class="table-message"> |
|||
// <div class="table-name">${icon.info.name}</div> |
|||
// <div class="table-line"></div> |
|||
// <div class="base-table-info"> |
|||
// <span class='table-info'>名称 :${icon.info.name}</span></br> |
|||
// <span class='table-info'>容量:${icon.info.installedPower}</span></br> |
|||
// <span class='table-info'>电压 :${icon.info.voltage}</span></br> |
|||
// <span class='table-info'>频率:${icon.info.frequency}</span></br> |
|||
// <span class='table-info'>接口数量 :${icon.info.interfaceCount}</span></br> |
|||
// <span class='table-info'>同时可用数量:${icon.info.simultaneouslyInterfaceCount}</span></br> |
|||
// </div> |
|||
// </div>` |
|||
// } |
|||
// const getBerthStr = (icon: any) => { |
|||
// return ` |
|||
// <div class="table-message"> |
|||
// <div class="table-name">${icon.info.berthName}</div> |
|||
// <div class="table-line"></div> |
|||
// <div class="base-table-info"> |
|||
// <span class='table-info'>泊位 :${icon.info.berthName}</span></br> |
|||
// <span class='table-info'>总电量:${icon.info.totalPower}</span></br> |
|||
// <span class='table-info'>更新时间 :${icon.info.updateTime}</span></br> |
|||
// <span class='table-info'>状态:${icon.info.status}</span></br> |
|||
// <span class='table-info'>接口规格 :${icon.info.InterfaceType}</span></br> |
|||
// <span class='table-info'>泊位水深:${icon.info.berthDepth}</span></br> |
|||
// </div> |
|||
// </div>` |
|||
// } |
|||
// const getShipStr = (icon: any) => { |
|||
// return ` |
|||
// <div class="table-message"> |
|||
// <div class="table-name">${icon.info.shipName}</div> |
|||
// <div class="table-line"></div> |
|||
// <div class="base-table-info"> |
|||
// <span class='table-info'>船名 :${icon.info.shipName}</span></br> |
|||
// <span class='table-info'>呼号:${icon.info.callSign}</span></br> |
|||
// <span class="table-info">船公司:${icon.info.shipCompany}</span></br> |
|||
// <span class="table-info">联系电话:${icon.info.phone}</span></br> |
|||
// <span class='table-info'>长度 :${icon.info.length}</span></br> |
|||
// <span class='table-info'>宽度:${icon.info.width}</span></br> |
|||
// <span class='table-info'>吨位 :${icon.info.tonnage}</span></br> |
|||
// <span class='table-info'>类型:${icon.info.type}</span></br> |
|||
// <span class='table-info'>货物名称:${icon.info.CommodityName}</span></br> |
|||
// <span class='table-info'>货物吨数:${icon.info.cargoWeight}</span></br> |
|||
// ${icon.reason == 9 ? `<span class='table-info'>岸电接入时间:${icon.info.startUsingTime}</span></br>` : `<span class='table-info'>岸电未使用原因:${reason.value[icon.reason]}</span></br>`} |
|||
// <span class='table-info'>计划离泊时间:${icon.info.scheduledDepartureTime}</span></br> |
|||
// ${icon.reason == 9 ? `<span class='table-info'>岸电用量:${icon.info.shorePowerConsumption}</span></br>` : ''} |
|||
// <span class='table-info'>辅机总功率:${icon.info.totalAuxiliaryPower}</span></br> |
|||
// </div> |
|||
// </div> |
|||
// ` |
|||
// } |
|||
// const getProblemStr = (icon: any) => { |
|||
// return ` |
|||
// <div class="table-message"> |
|||
// <div class="table-name">${icon.parent.info.shipName}</div> |
|||
// <div class="table-line"></div> |
|||
// <div class="base-table-info"> |
|||
// <span class='table-info'>船名 :${icon.parent.info.shipName}</span></br> |
|||
// <span class='table-info'>岸电未使用原因:${reason.value[icon.parent.reason]}</span></br> |
|||
// <span class='table-info'>计划离泊时间:${icon.parent.info.scheduledDepartureTime}</span></br> |
|||
// </div> |
|||
// </div> |
|||
// ` |
|||
// } |
|||
|
|||
let mapNum = 1 |
|||
const usingAlarm = ref([]) |
|||
const removeAlarm = () => { |
|||
for (let ships of usingAlarm.value) { |
|||
for (const alarm of usingAlarm.value[ships]) { |
|||
alarm.remove() |
|||
} |
|||
usingAlarm.value[ships] = [] |
|||
} |
|||
} |
|||
const buildAlarm = (icon:any, nowMapNum: number, radius: number = 1, timeOutTime: number = 50, color: string = Math.random() > 0.95 ? `rgba(255, 50, 50, 1)` :`rgba(50, 255, 20, 0.13)`) => { |
|||
setTimeout(() => { |
|||
if (nowMapNum !== mapNum) return |
|||
if (_map.value.getZoom() <= 15) { |
|||
const alarm = L.circle(icon.xy, { |
|||
radius: 50 * radius, |
|||
color: color, |
|||
stroke: false, |
|||
interactive: false, |
|||
}).addTo(_map.value); |
|||
if (!usingAlarm.value[icon.id]) usingAlarm.value[icon.id] = [] |
|||
usingAlarm.value[icon.id].push(alarm) |
|||
} |
|||
|
|||
if (radius > (6 * 18 / _map.value.getZoom())) { |
|||
for (let nowAlarm of usingAlarm.value[icon.id]) { |
|||
nowAlarm.remove() |
|||
} |
|||
usingAlarm.value[icon.id] = [] |
|||
buildAlarm(icon, nowMapNum, 1, 50, color) |
|||
} else ( |
|||
buildAlarm(icon, nowMapNum, radius + 1, timeOutTime + 2 ** radius / 2 , color) |
|||
) |
|||
}, timeOutTime) |
|||
} |
|||
|
|||
const svgs = { |
|||
interface_red: interface_red, |
|||
interface_yellow: interface_yellow, |
|||
interface_blue: interface_blue, |
|||
interface_green: interface_green, |
|||
ship_red: ship_red, |
|||
ship_yellow: ship_yellow, |
|||
ship_blue: ship_blue, |
|||
ship_green: ship_green, |
|||
ship_brown: ship_brown, |
|||
ship_problem: ship_problem, |
|||
shorepower_blue: shorepower_blue, |
|||
shorepower_green: shorepower_green, |
|||
problem: problem, |
|||
problem_red: problem_red |
|||
} |
|||
// 计算图标尺寸【不同缩放比例下】 |
|||
const countIconSize = (icon: any): [number, number] => { |
|||
let zoomRatio = 2 ** (20 - _map.value.getZoom()) |
|||
return [icon.width * icon.ratio / zoomRatio, icon.height * icon.ratio / zoomRatio] |
|||
} |
|||
// 计算图标中心点【不同缩放比例下】 |
|||
const countIconAnchor = (icon: any): [number, number] => { |
|||
let zoomRatio = 2 ** (21 - _map.value.getZoom()) |
|||
return [icon.width * icon.ratio / zoomRatio, icon.height * icon.ratio / zoomRatio] |
|||
} |
|||
// 计算文本尺寸【不同缩放比例下】 |
|||
const countFontSize = (text: any) => { |
|||
return text.fontSize / (1.7 ** (20 - _map.value.getZoom())) * 10 |
|||
} |
|||
// 构建绘制options |
|||
const buildOptions = (data: any) => { |
|||
try { |
|||
|
|||
if ((data.type && data.type === 'gon') || (data.type && data.type === 'line') || (!data.type && (type.value == 'gon' || type.value == 'line'))) return data |
|||
|
|||
if ((data.type && data.type === 'icon') || (!data.type && type.value == 'icon')) { |
|||
return { |
|||
icon: L.icon({ |
|||
iconAnchor: countIconAnchor(data), |
|||
iconSize: countIconSize(data), |
|||
iconUrl: svgs[data.icon] |
|||
}), |
|||
rotationAngle: data.rotationAngle, |
|||
rotationOrigin: "center center" |
|||
} |
|||
} |
|||
if ((data.type && data.type === 'text') || (!data.type && type.value == 'text')) { |
|||
const fontSize = countFontSize(data) |
|||
let textWidth = fontSize * data.name.length |
|||
for (let i = 0; i < data.name.length; i++) { |
|||
if ((data.name[i]) in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#']) textWidth = textWidth - 0.5 * fontSize |
|||
} |
|||
textWidth = textWidth * 1.2 |
|||
const tagAnchor = data.tagAnchorType === 1 ? [0, 0] : data.tagAnchorType === 2 ? [textWidth, 0] : data.tagAnchorType === 3 ? [0, fontSize] : data.tagAnchorType === 4 ? [textWidth, fontSize] : [textWidth / 2, fontSize / 2] |
|||
const style = ` |
|||
background-color:${data.background};border-radius: 5px;text-align: center; |
|||
color: ${data.color}; |
|||
width: ${textWidth}px; |
|||
font-size: ${fontSize}px; |
|||
font-style: oblique; |
|||
font-weight: ${data.fontSize * 33}; |
|||
cursor: grab;` |
|||
return { |
|||
icon: L.divIcon({ |
|||
className: data.name, |
|||
iconAnchor: tagAnchor, |
|||
html: `<div style="${style}">${data.name}</div>` |
|||
}) |
|||
} |
|||
} |
|||
} catch (e) { |
|||
console.log(e, data) |
|||
} |
|||
} |
|||
|
|||
const _map = ref<any>({_zoom: 14,_animateToCenter: {lat: 0, lng: 0}}) |
|||
const mapRef = ref(null); |
|||
const defaultData = ref({ |
|||
defCenter: {lat: 38.8422480135733, lng: 118.4933866580094}, |
|||
defZoom: 12, |
|||
mapName: 'map', |
|||
illustration: true |
|||
}) |
|||
const center = ref(defaultData.value.defCenter) |
|||
const zoom = ref(defaultData.value.defZoom) |
|||
const mouse = ref(defaultData.value.defCenter) |
|||
const type = ref('gon') // 1: 绘制区域 2: 绘制线 3: 绘制图标 4: 绘制文本 |
|||
|
|||
// 【区域】绘制参数 |
|||
const polygon = ref({ |
|||
stroke: true, |
|||
color:`rgb(50, 50, 50)`, |
|||
weight:1, |
|||
opacity:1, |
|||
fill:true, |
|||
fillColor:`rgb(255, 255, 200)`, |
|||
fillOpacity:1, |
|||
interactive:false, |
|||
smoothFactor:1, |
|||
xy:[] |
|||
}) |
|||
const usingPolygon = ref() |
|||
const drawingPolygon = () => { |
|||
if (usingPolygon.value) usingPolygon.value.remove() |
|||
usingPolygon.value = L.polygon(polygon.value.xy, buildOptions(polygon.value)).addTo(_map.value) |
|||
usingPolygon.value.on('click', () => { |
|||
type.value = 'text' |
|||
}) |
|||
} |
|||
|
|||
// 【线】绘制参数 |
|||
const polyline = ref({ |
|||
interactive: false, |
|||
color: `rgb(50, 50, 50)`, // 描边颜色 |
|||
dashArray: [10, 5], |
|||
weight: 1,// 描边宽度 |
|||
smoothFactor: 0, |
|||
xy: [], |
|||
}) |
|||
const usingPolyline = ref() |
|||
const drawingPolyline = () => { |
|||
if (usingPolyline.value) usingPolyline.value.remove() |
|||
usingPolyline.value = L.polyline(polyline.value.xy, buildOptions(polyline.value)).addTo(_map.value); |
|||
usingPolygon.value.on('click', () => { |
|||
type.value = 'text' |
|||
}) |
|||
} |
|||
|
|||
// 【图标】绘制参数 |
|||
const marker = ref({ |
|||
rotationAngle: 0, |
|||
width: 1000, |
|||
height: 5200, |
|||
ratio: 1, |
|||
iconType: 'ship', |
|||
icon: 'ship_green', |
|||
anchor: 'left', |
|||
xy: [], |
|||
}) |
|||
const usingMarker = ref() |
|||
const drawingMarker = () => { |
|||
if (usingMarker.value) usingMarker.value.remove() |
|||
if (marker.value.xy.length !== 2) return |
|||
usingMarker.value = L.marker(marker.value.xy, buildOptions(marker.value)).addTo(_map.value); |
|||
usingPolygon.value.on('click', () => { |
|||
type.value = 'text' |
|||
}) |
|||
} |
|||
|
|||
// 【文本】绘制参数 |
|||
const textType = ref('ship') |
|||
const text = ref({ |
|||
name: '浙能2', |
|||
xy: [38.94212905193746, 118.4492737054825], |
|||
// type: 0, |
|||
fontSize: 16, |
|||
tagAnchorType: 1, |
|||
background: 'rgba(255, 255, 255, 0.7)', |
|||
color: 'rgba(50, 50, 50, 1)', |
|||
anchor: 'left', |
|||
}) |
|||
const usingText = ref() |
|||
const drawingText = () => { |
|||
if (usingText.value) usingText.value.remove() |
|||
if (text.value.xy.length !== 2) return |
|||
usingText.value = L.marker(text.value.xy, buildOptions(text.value)).addTo(_map.value) |
|||
usingPolygon.value.on('click', () => { |
|||
type.value = 'text' |
|||
}) |
|||
} |
|||
|
|||
const getDrawingInfo = () => { |
|||
if (type.value === 'gon') { |
|||
return {type: type.value, ...polygon.value} |
|||
} else if (type.value === 'line') { |
|||
return {type: type.value, ...polyline.value} |
|||
} else if (type.value === 'icon') { |
|||
return {type: type.value, ...marker.value} |
|||
} else if (type.value === 'text') { |
|||
if (textType.value !== 'ship') { |
|||
const { anchor, ...textInfo} = text.value |
|||
return {type: type.value, ...textInfo} |
|||
} else { |
|||
return {type: type.value, ...text.value} |
|||
} |
|||
} |
|||
} |
|||
const doCopy = async () => { |
|||
const str = JSON.stringify(getDrawingInfo()) |
|||
try { |
|||
// 尝试使用现代API |
|||
await navigator.clipboard.writeText(str); |
|||
// console.log('复制成功!',str); |
|||
return |
|||
} catch (err) { |
|||
// 降级处理 |
|||
const textArea = document.createElement("textarea"); |
|||
textArea.value = str; |
|||
textArea.style.cssText = "position: fixed; top: -1000px; opacity: 0;"; |
|||
document.body.appendChild(textArea); |
|||
textArea.select(); |
|||
try { |
|||
document.execCommand('copy'); |
|||
// console.log('复制成功!',str); |
|||
} catch (err) { |
|||
alert('复制失败,请手动复制') |
|||
// console.log('复制失败,请手动复制'); |
|||
} |
|||
document.body.removeChild(textArea); |
|||
} |
|||
} |
|||
const copyData = async () => { |
|||
await doCopy() |
|||
} |
|||
const addDrawingList = async (event) => { |
|||
if (event.keyCode === 32 || event.key === ' ') { |
|||
event.preventDefault(); |
|||
if (type.value === 'gon') { |
|||
polygon.value.xy.push([mouse.value.lat, mouse.value.lng]) |
|||
drawingPolygon() |
|||
} else if (type.value === 'line') { |
|||
polyline.value.xy.push([mouse.value.lat, mouse.value.lng]) |
|||
drawingPolyline() |
|||
} else if (type.value === 'icon') { |
|||
marker.value.xy = [mouse.value.lat, mouse.value.lng] |
|||
drawingMarker() |
|||
} else if (type.value === 'text') { |
|||
text.value.xy = [mouse.value.lat, mouse.value.lng] |
|||
drawingText() |
|||
} |
|||
} else if (event.keyCode === 46 || event.key === 'Delete') { |
|||
event.preventDefault(); |
|||
if (type.value === 'gon') { |
|||
polygon.value.xy.pop() |
|||
drawingPolygon() |
|||
} else if (type.value === 'line') { |
|||
polyline.value.xy.pop() |
|||
drawingPolyline() |
|||
} else if (type.value === 'icon') { |
|||
marker.value.xy = [] |
|||
drawingMarker() |
|||
} else if (type.value === 'text') { |
|||
text.value.xy = [] |
|||
drawingText() |
|||
} |
|||
} else if (event.keyCode === 13 || event.key === 'Enter') { |
|||
await copyData() |
|||
} |
|||
} |
|||
const doDrawing = () => { |
|||
if (type.value === 'gon') { |
|||
drawingPolygon() |
|||
} else if (type.value === 'line') { |
|||
drawingPolyline() |
|||
} else if (type.value === 'icon') { |
|||
drawingMarker() |
|||
} else if (type.value === 'text') { |
|||
drawingText() |
|||
} |
|||
} |
|||
|
|||
const history = ref() |
|||
const usingHistory = ref([]) |
|||
const doHistory = ref(false) |
|||
const removeHistory = () => { |
|||
if (usingHistory.value) { |
|||
for (const item of usingHistory.value) { |
|||
item.remove() |
|||
} |
|||
usingHistory.value = [] |
|||
} |
|||
} |
|||
const drawingHistoryPolygon = (data: any) => { |
|||
if (_map.value.getZoom() < 12) return |
|||
const usingInfo = L.polygon(data.xy, buildOptions(data)).addTo(_map.value) |
|||
usingInfo.on('click', async () => { |
|||
if (doHistory.value) await drawingHistory(doHistory.value) |
|||
doHistory.value = true |
|||
polygon.value = data |
|||
type.value = 'gon' |
|||
usingInfo.remove() |
|||
doDrawing() |
|||
}) |
|||
usingHistory.value.push(usingInfo) |
|||
} |
|||
const drawingHistoryPolyline = (data: any) => { |
|||
if (_map.value.getZoom() < 12) return |
|||
const usingInfo = L.polyline(data.xy, buildOptions(data)).addTo(_map.value) |
|||
usingInfo.on('click', async () => { |
|||
if (doHistory.value) await drawingHistory(doHistory.value) |
|||
doHistory.value = true |
|||
polyline.value = data |
|||
type.value = 'line' |
|||
usingInfo.remove() |
|||
doDrawing() |
|||
}) |
|||
usingHistory.value.push(usingInfo) |
|||
} |
|||
const drawingHistoryMarker = (data: any) => { |
|||
if (data.iconType === 'ship') { |
|||
const nowMapNum = JSON.parse(JSON.stringify(mapNum)) |
|||
buildAlarm(data, nowMapNum) |
|||
} |
|||
if (_map.value.getZoom() < 12) return |
|||
const usingInfo = L.marker(data.xy, buildOptions(data)).addTo(_map.value) |
|||
usingInfo.on('click', async () => { |
|||
if (doHistory.value) await drawingHistory(doHistory.value) |
|||
doHistory.value = true |
|||
marker.value = data |
|||
type.value = 'icon' |
|||
usingInfo.remove() |
|||
doDrawing() |
|||
}) |
|||
usingHistory.value.push(usingInfo) |
|||
} |
|||
const drawingHistoryTest = (data: any) => { |
|||
if (_map.value.getZoom() < 12) return |
|||
const usingInfo = L.marker(data.xy, buildOptions(data)).addTo(_map.value) |
|||
usingInfo.on('click', async () => { |
|||
if (doHistory.value) await drawingHistory(doHistory.value) |
|||
doHistory.value = true |
|||
text.value = data |
|||
type.value = 'text' |
|||
usingInfo.remove() |
|||
doDrawing() |
|||
}) |
|||
usingHistory.value.push(usingInfo) |
|||
} |
|||
const drawingHistoryInfo = (data: any) => { |
|||
if (data.type === 'gon') { |
|||
drawingHistoryPolygon(data) |
|||
} else if (data.type === 'line') { |
|||
drawingHistoryPolyline(data) |
|||
} else if (data.type === 'icon') { |
|||
drawingHistoryMarker(data) |
|||
} else if (data.type === 'text') { |
|||
drawingHistoryTest(data) |
|||
} |
|||
} |
|||
const drawingHistory = async (justOne: boolean = false) => { |
|||
// if (!history.value) { |
|||
// history.value = await MapApi.getAllData() |
|||
// } |
|||
const dataInfo = history.value ? history.value : await MapApi.getAllData() |
|||
if (justOne) { |
|||
drawingHistoryInfo(getDrawingInfo()) |
|||
} else { |
|||
for (const item of dataInfo) { |
|||
if (!item.data) continue |
|||
const data = JSON.parse(item.data) |
|||
if (!data.xy) continue |
|||
drawingHistoryInfo(data) |
|||
} |
|||
} |
|||
} |
|||
|
|||
const buildMap = () => { |
|||
_map.value = L.map(defaultData.value.mapName, { |
|||
center: defaultData.value.defCenter, |
|||
zoom: defaultData.value.defZoom, |
|||
zoomControl: false, |
|||
attributionControl: false, |
|||
}) |
|||
L.tileLayer( |
|||
// 'http://150.138.79.224:8000/seamap/allmap/{z}/{y}/{x}.png', |
|||
// 'https://api.shipxy.com/h5s/api/3.5/sample?key=0cd1a6224aaa4b5ab1f3d0e79bb543cc&projection_type=wm&x={x}&y={y}&z={z}', |
|||
// 'https://m12.shipxy.com/tile.c?l=Na&m=o&x={x}&y={y}&z={z}', |
|||
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', |
|||
// '', |
|||
{ |
|||
maxZoom: 19, |
|||
minZoom: 5, |
|||
attribution: '' |
|||
}).addTo(_map.value); |
|||
|
|||
// 设置地图的最大边界 |
|||
const southWest = L.latLng(38.30071455572194, 117.07885023513526); // 西南角的坐标 |
|||
const northEast = L.latLng( 40.32351403031131, 119.9161164758117); // 东北角的坐标 |
|||
_map.value.setMaxBounds(L.latLngBounds(southWest, northEast)); |
|||
|
|||
|
|||
// 监听鼠标位置坐标 |
|||
_map.value.on('mousemove', (e) => { |
|||
mouse.value = e.latlng; |
|||
}); |
|||
|
|||
// 监听缩放级别变化 |
|||
_map.value.on('zoomend', async () => { |
|||
zoom.value = _map.value.getZoom(); |
|||
removeHistory() |
|||
removeAlarm() |
|||
mapNum++ |
|||
await drawingHistory() |
|||
doDrawing() |
|||
}) |
|||
|
|||
// 监听当前中心点坐标变化 |
|||
_map.value.on('moveend', () => { |
|||
center.value = _map.value.getCenter(); |
|||
}); |
|||
} |
|||
const buildBaseInfo = () => { |
|||
for (const item of baseInfo) { |
|||
if (item.xy) L.polygon(item.xy, item).addTo(_map.value) |
|||
} |
|||
} |
|||
|
|||
const exportImage = async () => { |
|||
try { |
|||
alert('功能暂不可用!') |
|||
} catch (error) { |
|||
console.error('地图导出失败:', error) |
|||
alert('地图导出失败,请重试') |
|||
} |
|||
} |
|||
/** 初始化 **/ |
|||
onMounted(() => { |
|||
buildMap() |
|||
buildBaseInfo() |
|||
window.addEventListener('keyup', addDrawingList) |
|||
drawingHistory() |
|||
}) |
|||
|
|||
|
|||
</script> |
|||
|
|||
<style > |
|||
.parent { |
|||
position: relative; /* 启用Grid布局 */ |
|||
} |
|||
|
|||
.child { |
|||
position: absolute; |
|||
top: 10px; |
|||
left: 20px; |
|||
z-index: 1; |
|||
width: 200px; |
|||
height: 150px; |
|||
background-color: rgba(30, 30, 30, 0.7); |
|||
border: 1px solid rgba(30, 30, 30, 0.4); |
|||
border-radius: 15px; |
|||
|
|||
} |
|||
.text-title { |
|||
margin-top: 10px; |
|||
font-size: 16px; |
|||
color: rgba(20, 200, 255, 1); |
|||
text-align: center; |
|||
font-weight: bold; |
|||
line-height: 30px; |
|||
text-shadow: 0 0 5px rgba(0, 0, 0, 1), 0 0 6px rgba(20, 200, 255, 0.3), 0 0 7px rgba(20, 200, 255, 0.2), 0 0 8px rgba(20, 200, 255, 0.1); |
|||
|
|||
} |
|||
.circle { |
|||
width: 10px; |
|||
height: 10px; |
|||
border-radius: 5px; |
|||
margin-left: 15px; |
|||
display: inline-block; |
|||
} |
|||
.circle-green { |
|||
background-color: rgba(50, 255, 100, 1); |
|||
} |
|||
.circle-yellow { |
|||
background-color: rgba(255, 150, 0, 1); |
|||
} |
|||
.circle-red { |
|||
background-color: rgba(255, 70, 70, 1); |
|||
} |
|||
.text-info { |
|||
margin-left: 8px; |
|||
margin-top: 8px; |
|||
display: inline-block; |
|||
} |
|||
.text-info-green { |
|||
color: rgba(50, 255, 100, 1); |
|||
} |
|||
.text-info-yellow { |
|||
color: rgba(255, 150, 0, 1); |
|||
} |
|||
.text-info-red { |
|||
color: rgba(255, 70, 70, 1); |
|||
} |
|||
.mapParent { |
|||
max-width: 100%; |
|||
max-height: 100%; |
|||
overflow: hidden; |
|||
} |
|||
.my-map { |
|||
height: 100vh; |
|||
background-color: #A3CCFF; |
|||
//transform: scale(1.4); |
|||
} |
|||
|
|||
.table-message { |
|||
width: 300px; |
|||
margin-top: 10px; |
|||
} |
|||
|
|||
.table-name { |
|||
margin-top: 25px; |
|||
font-size: 20px; |
|||
color: rgb(0, 200, 255); |
|||
} |
|||
.table-line { |
|||
min-height: 3px; |
|||
width: 100%; |
|||
margin-top: 10px; |
|||
margin-bottom: 10px; |
|||
background-color: rgb(0, 200, 255); |
|||
} |
|||
.base-table-info { |
|||
} |
|||
.table-info { |
|||
margin-top: 10px; |
|||
font-size: 16px; |
|||
line-height: 25px; |
|||
color: rgba(50, 50, 50, 1); |
|||
} |
|||
|
|||
|
|||
</style> |
|||
@ -0,0 +1,240 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="zh-CN"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title>CesiumJS 天地图纯影像示例</title> |
|||
|
|||
<link href="https://cesium.com/downloads/cesiumjs/releases/1.123/Build/Cesium/Widgets/widgets.css" rel="stylesheet"> |
|||
<script src="https://cesium.com/downloads/cesiumjs/releases/1.123/Build/Cesium/Cesium.js"></script> |
|||
|
|||
<style> |
|||
/* 确保 Cesium 容器占满整个浏览器窗口 */ |
|||
body { margin: 0; overflow: hidden; } |
|||
#cesiumContainer { width: 100%; height: 100vh; } |
|||
|
|||
/* 悬浮按钮样式 */ |
|||
.control-btn { |
|||
position: absolute; |
|||
z-index: 1000; |
|||
padding: 10px 15px; |
|||
background-color: rgba(0, 0, 0, 0.7); |
|||
color: white; |
|||
border: none; |
|||
border-radius: 5px; |
|||
cursor: pointer; |
|||
font-size: 14px; |
|||
box-shadow: 0 2px 5px rgba(0,0,0,0.3); |
|||
transition: background-color 0.3s; |
|||
} |
|||
|
|||
.control-btn:hover { |
|||
background-color: rgba(0, 0, 0, 0.9); |
|||
} |
|||
|
|||
#cameraInfoBtn { |
|||
top: 20px; |
|||
right: 20px; |
|||
} |
|||
|
|||
/* 视角切换按钮 */ |
|||
.view-buttons { |
|||
position: absolute; |
|||
bottom: 20px; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
display: flex; |
|||
gap: 10px; |
|||
z-index: 1000; |
|||
} |
|||
|
|||
.view-btn { |
|||
padding: 8px 16px; |
|||
background-color: rgba(0, 0, 0, 0.7); |
|||
color: white; |
|||
border: none; |
|||
border-radius: 5px; |
|||
cursor: pointer; |
|||
font-size: 14px; |
|||
box-shadow: 0 2px 5px rgba(0,0,0,0.3); |
|||
transition: background-color 0.3s; |
|||
} |
|||
|
|||
.view-btn:hover { |
|||
background-color: rgba(0, 0, 0, 0.9); |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<div id="cesiumContainer"></div> |
|||
<button id="cameraInfoBtn" class="control-btn">获取当前视角参数</button> |
|||
|
|||
<!-- 视角切换按钮 --> |
|||
<div class="view-buttons"> |
|||
<button class="view-btn" data-view="overview">全局视角</button> |
|||
<button class="view-btn" data-view="ship1">船1视角</button> |
|||
<button class="view-btn" data-view="ship2">船2视角</button> |
|||
<button class="view-btn" data-view="ship3">船3视角</button> |
|||
<button class="view-btn" data-view="ship4">船4视角</button> |
|||
</div> |
|||
|
|||
<script type="module"> |
|||
// ---------------------------------------------------------------------- |
|||
// ** 请替换为您申请的天地图密钥 ** |
|||
// ---------------------------------------------------------------------- |
|||
const TDT_KEY = 'b19d3ad72716d1a28cf77836dfa19a71'; |
|||
|
|||
// 步骤 1: 初始化 Viewer 并配置为使用天地图影像和平坦地形 |
|||
const viewer = new Cesium.Viewer('cesiumContainer', { |
|||
// **核心设置:禁用所有默认影像,我们将手动添加天地图** |
|||
imageryProvider: false, |
|||
|
|||
// **使用平坦地形,避免依赖 Cesium Ion** |
|||
terrainProvider: new Cesium.EllipsoidTerrainProvider(), |
|||
|
|||
// 禁用所有不必要的UI控件 |
|||
timeline: false, |
|||
animation: false, |
|||
baseLayerPicker: false, |
|||
geocoder: false, |
|||
sceneModePicker: false, |
|||
navigationHelpButton: false, |
|||
infoBox: false, |
|||
fullscreenButton: false, |
|||
homeButton: false, |
|||
|
|||
// 启用抗锯齿和其他渲染优化 |
|||
contextOptions: { |
|||
webgl: { |
|||
antialias: true |
|||
} |
|||
} |
|||
}); |
|||
|
|||
// 禁用所有鼠标和键盘的相机控制操作 |
|||
viewer.scene.screenSpaceCameraController.enableRotate = false; |
|||
viewer.scene.screenSpaceCameraController.enableTranslate = false; |
|||
viewer.scene.screenSpaceCameraController.enableZoom = false; |
|||
viewer.scene.screenSpaceCameraController.enableTilt = false; |
|||
viewer.scene.screenSpaceCameraController.enableLook = false; |
|||
|
|||
// 渲染优化设置 |
|||
// 启用抗锯齿 |
|||
viewer.scene.postProcessStages.fxaa.enabled = true; |
|||
|
|||
// 启用深度测试,确保模型能够被地形正确遮挡 |
|||
viewer.scene.globe.depthTestAgainstTerrain = true; |
|||
|
|||
// 步骤 2: 添加天地图卫星影像底图 (img: 卫星图层, w: WGS84坐标系) |
|||
const tdtImage = new Cesium.WebMapTileServiceImageryProvider({ |
|||
// URL 中 LAYER=img 表示卫星影像图层 |
|||
url: "http://t{s}.tianditu.gov.cn/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=" + TDT_KEY, |
|||
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], |
|||
layer: 'tdtImgLayer', |
|||
style: 'default', |
|||
format: 'tiles', |
|||
tileMatrixSetID: 'w', // 确保使用 WGS84 坐标系 |
|||
maximumLevel: 18 |
|||
}); |
|||
|
|||
// 步骤 3: 将图层添加到 Viewer 中 |
|||
viewer.imageryLayers.addImageryProvider(tdtImage); |
|||
|
|||
// **注意:由于您要求不添加标注层,因此这里不添加 tdtCVA 或 tdtCIA** |
|||
|
|||
// 引入我们自定义的标记和定位功能 |
|||
import { initMarkerAndPosition } from './src/cesium-utils.js'; |
|||
|
|||
// 初始化标记和定位 |
|||
initMarkerAndPosition(viewer); |
|||
|
|||
// 定义预设视角参数 |
|||
const presetViews = { |
|||
overview: { |
|||
destination: Cesium.Cartesian3.fromDegrees(118.4603328835826, 38.953967794772765, 560.0105923892418), |
|||
orientation: { |
|||
heading: Cesium.Math.toRadians(231.0260194269599), |
|||
pitch: Cesium.Math.toRadians(-24.749471814600415), |
|||
roll: Cesium.Math.toRadians(0.005508519138937096) |
|||
} |
|||
}, |
|||
ship1: { |
|||
destination: Cesium.Cartesian3.fromDegrees(118.45467237056748 + 0.005, 38.94345692673452, 150), // 在船的前方 |
|||
orientation: { |
|||
heading: Cesium.Math.toRadians(212), // 朝向船的位置 (180+32) |
|||
pitch: Cesium.Math.toRadians(-15), |
|||
roll: 0 |
|||
} |
|||
}, |
|||
ship2: { |
|||
destination: Cesium.Cartesian3.fromDegrees(118.45183602217774 + 0.005, 38.94485094840323, 150), // 在船的前方 |
|||
orientation: { |
|||
heading: Cesium.Math.toRadians(212), // 朝向船的位置 (180+32) |
|||
pitch: Cesium.Math.toRadians(-15), |
|||
roll: 0 |
|||
} |
|||
}, |
|||
ship3: { |
|||
destination: Cesium.Cartesian3.fromDegrees(118.4468305964142 + 0.005, 38.947237470602076, 150), // 在船的前方 |
|||
orientation: { |
|||
heading: Cesium.Math.toRadians(212), // 朝向船的位置 (180+32) |
|||
pitch: Cesium.Math.toRadians(-15), |
|||
roll: 0 |
|||
} |
|||
}, |
|||
ship4: { |
|||
destination: Cesium.Cartesian3.fromDegrees(118.44446808752532 + 0.005, 38.94835610136433, 150), // 在船的前方 |
|||
orientation: { |
|||
heading: Cesium.Math.toRadians(212), // 朝向船的位置 (180+32) |
|||
pitch: Cesium.Math.toRadians(-15), |
|||
roll: 0 |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// 设置初始视角 |
|||
viewer.camera.setView(presetViews.overview); |
|||
|
|||
// 添加按钮点击事件监听器 |
|||
document.getElementById('cameraInfoBtn').addEventListener('click', function() { |
|||
// 获取当前相机位置 |
|||
const camera = viewer.camera; |
|||
const position = camera.position; |
|||
const cartographic = Cesium.Cartographic.fromCartesian(position); |
|||
|
|||
// 转换为度数 |
|||
const longitude = Cesium.Math.toDegrees(cartographic.longitude); |
|||
const latitude = Cesium.Math.toDegrees(cartographic.latitude); |
|||
const height = cartographic.height; |
|||
|
|||
// 获取相机方向 |
|||
const heading = Cesium.Math.toDegrees(camera.heading); |
|||
const pitch = Cesium.Math.toDegrees(camera.pitch); |
|||
const roll = Cesium.Math.toDegrees(camera.roll); |
|||
|
|||
// 输出到控制台 |
|||
console.log('当前相机视角参数:'); |
|||
console.log('位置 - 经度:', longitude, '纬度:', latitude, '高度:', height); |
|||
console.log('方向 - 航向角:', heading, '俯仰角:', pitch, '翻滚角:', roll); |
|||
|
|||
// 显示提示信息 |
|||
alert('相机参数已输出到控制台,请打开开发者工具查看。'); |
|||
}); |
|||
|
|||
// 添加视角切换按钮事件监听器 |
|||
document.querySelectorAll('.view-btn').forEach(button => { |
|||
button.addEventListener('click', function() { |
|||
const viewName = this.getAttribute('data-view'); |
|||
const viewParams = presetViews[viewName]; |
|||
|
|||
if (viewParams) { |
|||
viewer.camera.flyTo({ |
|||
destination: viewParams.destination, |
|||
orientation: viewParams.orientation, |
|||
duration: 2.0 // 动画持续时间(秒) |
|||
}); |
|||
} |
|||
}); |
|||
}); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,529 @@ |
|||
<template> |
|||
<div> |
|||
<div ref="cesiumContainerRef" class="cesium-container"></div> |
|||
<div class="btn-group"> |
|||
<!-- <el-button class="get-view-btn" size="small" type="primary" @click="getCurrentViewInfo" |
|||
style="margin-right: 10px;">获取当前视角</el-button> --> |
|||
<!-- <el-button class="view-btn" size="small" type="success" @click="switchView('overview')" |
|||
style="margin-right: 10px;">概览视角</el-button> --> |
|||
<!-- <el-button class="view-btn" size="small" type="warning" @click="switchView('view1')" |
|||
style="margin-right: 10px;">视角1</el-button> |
|||
<el-button class="view-btn" size="small" type="warning" @click="switchView('view2')" |
|||
style="margin-right: 10px;">视角2</el-button> --> |
|||
</div> |
|||
</div> |
|||
|
|||
</template> |
|||
|
|||
<script setup> |
|||
import { onMounted, onBeforeUnmount, ref } from 'vue'; |
|||
import coordtransform from 'coordtransform'; |
|||
import { MapApi } from "@/api/shorepower/map"; |
|||
import { toRaw } from 'vue' |
|||
// ⚠️ 注意:通过 window 访问全局 Cesium 对象 |
|||
const Cesium = window.Cesium; |
|||
|
|||
let viewer = null; |
|||
const cesiumContainerRef = ref(null); // 引用 DOM 元素 |
|||
const history = ref(null); // 历史数据 |
|||
const dataWithModels = ref([]); // 存储带有模型实例的数据列表 |
|||
|
|||
// 定义预设视角参数 |
|||
const presetViews = { |
|||
overview: { |
|||
"longitude": 118.5132903711312, |
|||
"latitude": 38.84648563549342, |
|||
"height": 12675.768680075478, |
|||
"heading": 353.6789759103708, |
|||
"pitch": -36.657258995301596, |
|||
"roll": 0.0343469697692715 |
|||
} |
|||
}; |
|||
|
|||
const createView = (obj) => { |
|||
return { |
|||
destination: Cesium.Cartesian3.fromDegrees(obj.longitude, obj.latitude, obj.height), |
|||
orientation: { |
|||
heading: Cesium.Math.toRadians(obj.heading), |
|||
pitch: Cesium.Math.toRadians(obj.pitch), |
|||
roll: Cesium.Math.toRadians(obj.roll) |
|||
} |
|||
} |
|||
} |
|||
|
|||
onMounted(async () => { |
|||
if (!Cesium) { |
|||
console.error("Cesium 对象未找到,请检查 index.html 文件!"); |
|||
return; |
|||
} |
|||
|
|||
// 步骤 1: 初始化 Viewer 并配置为使用高德地图影像和平坦地形 |
|||
try { |
|||
viewer = new Cesium.Viewer(cesiumContainerRef.value, { |
|||
// **核心设置:禁用所有默认影像,我们将手动添加高德地图** |
|||
imageryProvider: false, |
|||
|
|||
// **使用平坦地形,避免依赖 Cesium Ion** |
|||
terrainProvider: new Cesium.EllipsoidTerrainProvider(), |
|||
// sceneMode: Cesium.SceneMode.COLUMBUS_VIEW, |
|||
// 禁用所有不必要的UI控件 |
|||
timeline: false, |
|||
animation: false, |
|||
baseLayerPicker: false, |
|||
geocoder: false, |
|||
sceneModePicker: false, |
|||
navigationHelpButton: false, |
|||
infoBox: false, |
|||
fullscreenButton: false, |
|||
homeButton: false, |
|||
|
|||
// 启用抗锯齿和其他渲染优化 |
|||
contextOptions: { |
|||
webgl: { |
|||
antialias: true |
|||
} |
|||
} |
|||
}); |
|||
|
|||
|
|||
|
|||
// 禁用所有鼠标和键盘的相机控制操作 |
|||
/* viewer.scene.screenSpaceCameraController.enableRotate = false; |
|||
viewer.scene.screenSpaceCameraController.enableTranslate = false; |
|||
viewer.scene.screenSpaceCameraController.enableZoom = false; |
|||
viewer.scene.screenSpaceCameraController.enableTilt = false; |
|||
viewer.scene.screenSpaceCameraController.enableLook = false; */ |
|||
|
|||
// 渲染优化设置 |
|||
// 启用抗锯齿 |
|||
viewer.scene.postProcessStages.fxaa.enabled = true; |
|||
|
|||
// 启用深度测试,确保模型能够被地形正确遮挡 |
|||
viewer.scene.globe.depthTestAgainstTerrain = true; |
|||
|
|||
// 启用时钟动画,确保模型能够根据时间更新 |
|||
viewer.clock.shouldAnimate = true; |
|||
|
|||
viewer.scene.screenSpaceCameraController.minimumZoomDistance = 200; |
|||
// 步骤 2: 添加高德地图卫星影像底图 |
|||
const gaodeImage = new Cesium.UrlTemplateImageryProvider({ |
|||
url: "https://webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}", |
|||
subdomains: ['1', '2', '3', '4'], |
|||
layer: 'gaodeImgLayer', |
|||
style: 'default', |
|||
format: 'image/png', |
|||
maximumLevel: 16 |
|||
}); |
|||
const dataInfo = history.value ? history.value : await MapApi.getAllData() |
|||
const shipData = await MapApi.getShipInfo({ |
|||
harborDistrictId: 1 |
|||
}) |
|||
console.log('shipData', shipData) |
|||
|
|||
// const unitedData = |
|||
|
|||
// 通用添加函数,遍历dataInfo并创建标记 |
|||
const addMarkersFromDataInfo = (dataInfo) => { |
|||
// 更严格的数组检查 |
|||
if (!dataInfo || !Array.isArray(dataInfo) || dataInfo.length === 0) { |
|||
console.log('No valid dataInfo array provided'); |
|||
return []; |
|||
} |
|||
|
|||
// 创建新数组存储带有模型实例的数据 |
|||
const dataWithModelsArray = []; |
|||
|
|||
console.log(`Processing ${dataInfo.length} items`); |
|||
|
|||
dataInfo.forEach((item, index) => { |
|||
// 检查基本数据结构 |
|||
if (!item) { |
|||
console.warn(`Item at index ${index} is null or undefined`); |
|||
return; |
|||
} |
|||
|
|||
try { |
|||
// 创建包含模型实例的数据项副本 |
|||
let itemWithModel = { ...item }; |
|||
|
|||
// 解析data字段为JSON对象 |
|||
let dataObj; |
|||
if (typeof item.data === 'string') { |
|||
try { |
|||
dataObj = JSON.parse(item.data); |
|||
} catch (parseError) { |
|||
console.warn(`Failed to parse data for item ${item.id || index}:`, parseError); |
|||
dataWithModelsArray.push(itemWithModel); // 添加未解析成功的数据项 |
|||
return; |
|||
} |
|||
} else { |
|||
dataObj = item.data; |
|||
} |
|||
|
|||
// 检查dataObj是否有效 |
|||
if (!dataObj) { |
|||
console.warn(`No data object found for item ${item.id || index}`); |
|||
dataWithModelsArray.push(itemWithModel); // 添加无数据对象的数据项 |
|||
return; |
|||
} |
|||
|
|||
// 获取坐标信息 - 更严格的验证 |
|||
let longitude, latitude; |
|||
let wgsLon, wgsLat; |
|||
if (dataObj.xy && Array.isArray(dataObj.xy) && dataObj.xy.length >= 2) { |
|||
const wgsCoords = coordtransform.wgs84togcj02(dataObj.xy[1], dataObj.xy[0]); |
|||
wgsLon = wgsCoords[0]; |
|||
wgsLat = wgsCoords[1]; |
|||
// 确保坐标是有效数字 |
|||
latitude = wgsLat; |
|||
longitude = wgsLon; |
|||
// 检查坐标是否为有效数字 |
|||
if (isNaN(latitude) || isNaN(longitude)) { |
|||
console.warn(`Invalid coordinates for item ${item.id || index}:`, dataObj.xy); |
|||
dataWithModelsArray.push(itemWithModel); // 添加坐标无效的数据项 |
|||
return; |
|||
} |
|||
|
|||
// 检查坐标范围(简单验证) |
|||
if (Math.abs(latitude) > 90 || Math.abs(longitude) > 180) { |
|||
console.warn(`Coordinates out of range for item ${item.id || index}:`, dataObj.xy[1], dataObj.xy[0]); |
|||
dataWithModelsArray.push(itemWithModel); // 添加坐标超出范围的数据项 |
|||
return; |
|||
} |
|||
} else { |
|||
console.warn('无效的坐标信息:', item); |
|||
dataWithModelsArray.push(itemWithModel); // 添加无有效坐标的数据项 |
|||
return; |
|||
} |
|||
|
|||
if (dataObj.icon === 'ship_green') { |
|||
const itemShipInfo = shipData.find(shipItem => (shipItem.shorePower.id === item.parentId) && item.type === 5) |
|||
const position = Cesium.Cartesian3.fromDegrees(wgsLon, wgsLat, 15); |
|||
const statusPosition = Cesium.Cartesian3.fromDegrees(wgsLon, wgsLat, 1); |
|||
const labelPosition = Cesium.Cartesian3.fromDegrees(wgsLon, wgsLat, 35); |
|||
// 投放船模型 |
|||
const shipModel = viewer.entities.add({ |
|||
name: 'Cargo Ship Model', |
|||
position: position, |
|||
orientation: Cesium.Transforms.headingPitchRollQuaternion( |
|||
position, |
|||
new Cesium.HeadingPitchRoll( |
|||
Cesium.Math.toRadians(dataObj.rotationAngle), // 航向角 (绕Z轴旋转) |
|||
Cesium.Math.toRadians(0), // 俯仰角 (绕Y轴旋转) |
|||
Cesium.Math.toRadians(0) // 翻滚角 (绕X轴旋转) |
|||
) |
|||
), |
|||
model: { |
|||
uri: '/model/cargo_ship_07.glb', |
|||
scale: 1.5, // 调整模型大小 |
|||
// minimumPixelSize: 100, // 确保模型至少显示为50像素大小 |
|||
// 启用深度测试,使模型能够被地形遮挡 |
|||
enableDepthTest: true, |
|||
// 启用背光剔除,提高渲染性能 |
|||
backFaceCulling: true |
|||
} |
|||
}); |
|||
|
|||
// 保存模型实例到数据项 |
|||
itemWithModel.modelInstance = shipModel; |
|||
itemWithModel.modelType = 'ship'; |
|||
itemWithModel = { ...itemWithModel, ...itemShipInfo }; |
|||
|
|||
viewer.entities.add({ |
|||
position: labelPosition, // 船上方约10米 |
|||
label: { |
|||
text: itemShipInfo.shipBasicInfo.name || `Marker-${item.id || index}`, |
|||
font: '12px sans-serif', |
|||
fillColor: Cesium.Color.WHITE, |
|||
outlineColor: Cesium.Color.BLACK, |
|||
outlineWidth: 2, |
|||
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|||
pixelOffset: new Cesium.Cartesian2(0, -30), // 偏移量,避免与模型重叠 |
|||
disableDepthTestDistance: Number.POSITIVE_INFINITY // 始终可见 |
|||
} |
|||
}); |
|||
const overlayBillboard = viewer.entities.add({ |
|||
position: statusPosition, |
|||
billboard: { |
|||
image: '/img/故障.png', |
|||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
|||
verticalOrigin: Cesium.VerticalOrigin.CENTER, |
|||
disableDepthTestDistance: Number.POSITIVE_INFINITY, |
|||
scale: new Cesium.CallbackProperty(function (time, result) { |
|||
// t 会随着时间不断变化 |
|||
const t = Cesium.JulianDate.toDate(time).getTime() / 1000; |
|||
const pulse = 0.6 + Math.sin(t * 4) * 0.2; // (基准0.6, 幅度±0.2) |
|||
return pulse; |
|||
}, false) |
|||
} |
|||
}); |
|||
} |
|||
if (dataObj.type === 'text') { |
|||
const labelPosition = Cesium.Cartesian3.fromDegrees(wgsLon, wgsLat, 35); |
|||
viewer.entities.add({ |
|||
position: labelPosition, // 船上方约10米 |
|||
label: { |
|||
text: dataObj.name || `Marker-${item.id || index}`, |
|||
font: '20px sans-serif', |
|||
fillColor: Cesium.Color.WHITE, |
|||
outlineColor: Cesium.Color.BLACK, |
|||
outlineWidth: 2, |
|||
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|||
pixelOffset: new Cesium.Cartesian2(0, -30), // 偏移量,避免与模型重叠 |
|||
disableDepthTestDistance: Number.POSITIVE_INFINITY // 始终可见 |
|||
} |
|||
}); |
|||
} |
|||
if (dataObj.type === 'icon' && (dataObj.icon === 'interface_blue' || dataObj.icon === 'interface_red')) { |
|||
const position = Cesium.Cartesian3.fromDegrees(wgsLon, wgsLat, 1); |
|||
const labelPosition = Cesium.Cartesian3.fromDegrees(wgsLon, wgsLat, 5); |
|||
// 投放岸电箱模型 |
|||
const electricalBoxModel = viewer.entities.add({ |
|||
name: 'Electrical Box Model', |
|||
position: position, |
|||
orientation: Cesium.Transforms.headingPitchRollQuaternion( |
|||
position, |
|||
new Cesium.HeadingPitchRoll( |
|||
Cesium.Math.toRadians(dataObj.rotationAngle), // 航向角 (绕Z轴旋转) |
|||
Cesium.Math.toRadians(0), // 俯仰角 (绕Y轴旋转) |
|||
Cesium.Math.toRadians(0) // 翻滚角 (绕X轴旋转) |
|||
) |
|||
), |
|||
model: { |
|||
uri: '/model/electrical_box.glb', |
|||
scale: 1, // 调整模型大小 |
|||
// minimumPixelSize: 10, // 确保模型至少显示为50像素大小 |
|||
// 启用深度测试,使模型能够被地形遮挡 |
|||
enableDepthTest: true, |
|||
// 启用背光剔除,提高渲染性能 |
|||
backFaceCulling: true |
|||
} |
|||
}); |
|||
|
|||
// 保存模型实例到数据项 |
|||
itemWithModel.modelInstance = electricalBoxModel; |
|||
itemWithModel.modelType = 'electrical_box'; |
|||
|
|||
viewer.entities.add({ |
|||
position: labelPosition, // 船上方约10米 |
|||
label: { |
|||
text: '岸电箱' || `Marker-${item.id || index}`, |
|||
font: '10px sans-serif', |
|||
fillColor: Cesium.Color.WHITE, |
|||
outlineColor: Cesium.Color.BLACK, |
|||
outlineWidth: 2, |
|||
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|||
pixelOffset: new Cesium.Cartesian2(0, -30), // 偏移量,避免与模型重叠 |
|||
disableDepthTestDistance: Number.POSITIVE_INFINITY // 始终可见 |
|||
} |
|||
}); |
|||
} |
|||
|
|||
// 创建红点标记 |
|||
/* const entity = viewer.entities.add({ |
|||
name: item.name || `Marker-${item.id || index}`, |
|||
position: Cesium.Cartesian3.fromDegrees(wgsLon, wgsLat, 1), |
|||
point: { |
|||
pixelSize: 10, |
|||
color: Cesium.Color.RED, |
|||
outlineColor: Cesium.Color.WHITE, |
|||
outlineWidth: 2 |
|||
}, |
|||
// 可以添加标签显示名称 |
|||
label: { |
|||
text: item.name || `Marker-${item.id || index}`, |
|||
font: '14px sans-serif', |
|||
fillColor: Cesium.Color.WHITE, |
|||
outlineColor: Cesium.Color.BLACK, |
|||
outlineWidth: 2, |
|||
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, |
|||
pixelOffset: new Cesium.Cartesian2(0, -15) |
|||
} |
|||
}); |
|||
// 保存点标记实例到数据项 |
|||
itemWithModel.modelInstance = entity; |
|||
itemWithModel.modelType = 'point'; |
|||
*/ |
|||
|
|||
// 将处理后的数据项添加到新数组 |
|||
dataWithModelsArray.push(itemWithModel); |
|||
} catch (error) { |
|||
console.error('Error processing item:', item, error); |
|||
// 创建一个基本的数据项副本并添加到数组 |
|||
dataWithModelsArray.push({ ...item }); |
|||
} |
|||
}); |
|||
|
|||
return dataWithModelsArray; |
|||
}; |
|||
|
|||
// 步骤 3: 将图层添加到 Viewer 中 |
|||
viewer.imageryLayers.addImageryProvider(gaodeImage); |
|||
|
|||
// 调用通用函数创建标记并获取带有模型实例的数据 |
|||
dataWithModels.value = addMarkersFromDataInfo(dataInfo); |
|||
|
|||
// 设置初始视角 |
|||
viewer.camera.flyTo(createView(presetViews.overview)); |
|||
// 设置显示高度阈值 |
|||
const SHOW_HEIGHT = 30000; // 高度 > 5000m 才显示模型等信息 |
|||
// const targets = []; // 把需要控制的 entities push 进来 |
|||
const targets = dataWithModels.value |
|||
.filter(item => item.modelInstance) |
|||
.map(item => toRaw(item.modelInstance)); |
|||
console.log('targets', targets) |
|||
viewer.camera.changed.addEventListener(() => { |
|||
// 这个函数会在相机的任何属性发生变化后立即被调用。 |
|||
const height = viewer.camera.positionCartographic.height; |
|||
// console.log("相机高度(即缩放级别)已变化:", height.toFixed(2), "米"); |
|||
|
|||
// 控制模型显示/隐藏 |
|||
const visible = height <= SHOW_HEIGHT; // 1000m内才显示模型等信息 |
|||
targets.forEach(entity => { |
|||
if (entity.show !== visible) { |
|||
entity.show = visible; |
|||
} |
|||
}); |
|||
|
|||
// 其他缩放级别逻辑 |
|||
if (height < 100000) { |
|||
// 放大到街景级别 |
|||
console.log("当前处于近距离缩放级别。"); |
|||
} else if (height > 5000000) { |
|||
// 缩小到全球级别 |
|||
console.log("当前处于远距离缩放级别。"); |
|||
} |
|||
}); |
|||
|
|||
// 添加地图点击事件 |
|||
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); |
|||
handler.setInputAction(function (movement) { |
|||
console.log('地图点击事件触发'); |
|||
|
|||
// 尝试多种方式获取点击位置 |
|||
const ray = viewer.camera.getPickRay(movement.position); |
|||
|
|||
// 方法1: 从地球表面拾取 |
|||
let cartesian = viewer.scene.globe.pick(ray, viewer.scene); |
|||
|
|||
// 如果从地球表面拾取失败,尝试从场景中拾取 |
|||
if (!cartesian) { |
|||
cartesian = viewer.scene.pickPosition(movement.position); |
|||
console.log('使用场景拾取方法'); |
|||
} |
|||
|
|||
// 如果仍然失败,尝试使用相机计算位置 |
|||
if (!cartesian) { |
|||
// 获取屏幕中心点作为替代方案(仅用于调试) |
|||
console.log('无法从点击位置获取精确坐标'); |
|||
return; |
|||
} |
|||
|
|||
if (cartesian) { |
|||
const cartographic = Cesium.Cartographic.fromCartesian(cartesian); |
|||
if (cartographic) { |
|||
const longitude = Cesium.Math.toDegrees(cartographic.longitude); |
|||
const latitude = Cesium.Math.toDegrees(cartographic.latitude); |
|||
const gcj02 = coordtransform.gcj02towgs84(longitude, latitude); |
|||
console.log('点击位置经纬度:', { |
|||
longitude: gcj02[0], |
|||
latitude: gcj02[1] |
|||
}); |
|||
} else { |
|||
console.log('无法从笛卡尔坐标转换为大地坐标'); |
|||
} |
|||
} else { |
|||
console.log('未能获取到地球表面的点击位置'); |
|||
} |
|||
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); |
|||
|
|||
// 确保启用场景的鼠标事件 |
|||
viewer.scene.screenSpaceCameraController.enableInputs = true; |
|||
|
|||
// 启用拾取透明物体 |
|||
viewer.scene.useDepthPicking = true; |
|||
|
|||
console.log('Cesium 高德地图 Viewer 初始化成功'); |
|||
} catch (error) { |
|||
console.error('Cesium Viewer 初始化失败:', error); |
|||
} |
|||
}); |
|||
|
|||
// 视角切换方法 |
|||
const switchView = (viewName) => { |
|||
const viewParams = presetViews[viewName]; |
|||
if (viewParams && viewer) { |
|||
viewer.camera.flyTo({ |
|||
...createView(viewParams), |
|||
duration: 2.0 // 动画持续时间(秒) |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
// 视角切换方法 |
|||
const switchModelView = (view) => { |
|||
const modelInstance = toRaw(view); |
|||
console.log(modelInstance) |
|||
if (viewer && view) { |
|||
viewer.flyTo(modelInstance); |
|||
} |
|||
}; |
|||
|
|||
// 获取当前视角信息的方法 |
|||
const getCurrentViewInfo = () => { |
|||
if (!viewer) { |
|||
console.warn('Viewer 尚未初始化'); |
|||
return null; |
|||
} |
|||
const camera = viewer.camera; |
|||
|
|||
const position = camera.position; // 世界笛卡尔坐标系 x,y,z |
|||
const cartographic = Cesium.Cartographic.fromCartesian(position); |
|||
console.log( |
|||
{ |
|||
longitude: Cesium.Math.toDegrees(cartographic.longitude), |
|||
latitude: Cesium.Math.toDegrees(cartographic.latitude), |
|||
height: cartographic.height, |
|||
heading: Cesium.Math.toDegrees(camera.heading), |
|||
pitch: Cesium.Math.toDegrees(camera.pitch), |
|||
roll: Cesium.Math.toDegrees(camera.roll) |
|||
} |
|||
) |
|||
|
|||
}; |
|||
|
|||
// 暴露方法和数据给父组件使用 |
|||
defineExpose({ |
|||
switchView, |
|||
dataWithModels, |
|||
switchModelView |
|||
}); |
|||
|
|||
onBeforeUnmount(() => { |
|||
// 销毁 Viewer,释放 WebGL 资源 |
|||
if (viewer) { |
|||
viewer.destroy(); |
|||
viewer = null; |
|||
console.log('Cesium Viewer 已销毁'); |
|||
} |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.cesium-container { |
|||
width: 100%; |
|||
height: 100vh; |
|||
margin: 0; |
|||
padding: 0; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.btn-group { |
|||
position: absolute; |
|||
top: 10px; |
|||
z-index: 1000; |
|||
display: flex; |
|||
gap: 12rpx; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,703 @@ |
|||
|
|||
|
|||
|
|||
const tagsData: any = [ |
|||
{name: '华能曹妃甸港口', xy: [38.9498140921284, 118.4373164176941], type: 0, fontSize: 18, tagAnchorType: 1, background: false, |
|||
parent: {}, |
|||
tags:[], |
|||
icons: [ |
|||
// {xy: [38.94223753278567, 118.44984233379365], type: 1, icon: 'shorepower_blue', rotationAngle: 0,
|
|||
// info: {name: '1号岸电设备', installedPower: '2000千伏安', voltage: '0.4/0.44千伏', frequency: '50/60赫兹', interfaceCount: '2', simultaneouslyInterfaceCount: '1'},
|
|||
// parent: {},
|
|||
// tags:[],
|
|||
// icons: [
|
|||
{xy: [38.94250178103962, 118.44926834106447], type: 2, icon: 'interface_yellow', rotationAngle: -58.8, |
|||
info: {berthName: '1泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '1泊位', xy: [38.942729866856865, 118.44900012016298], type: 0, fontSize: 16, tagAnchorType: 3, background: false, tags:[], parent: {}, icons: [],}, |
|||
], |
|||
icons:[ |
|||
{xy: [38.94241835068678, 118.44873189926149], type: 3, icon: 'ship_problem', rotationAngle: -59, reason: 7, status: 3, |
|||
info: {shipName: '浙能2', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '浙能2', xy: [38.94212905193746, 118.4492737054825], type: 0, fontSize: 16, tagAnchorType: 2, background: true, parent: {}, tags:[], icons: [],}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.941786918944366, 118.44942927360536], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
// ]},
|
|||
|
|||
|
|||
// {xy: [38.943643596453846, 118.44687044620515], type: 1, icon: 'shorepower_blue', rotationAngle: 0,
|
|||
// info: {name: '2号岸电设备', installedPower: '2000千伏安', voltage: '0.4/0.44千伏', frequency: '50/60赫兹', interfaceCount: '2', simultaneouslyInterfaceCount: '1'},
|
|||
// parent: {},
|
|||
// tags:[],
|
|||
// icons: [
|
|||
{xy: [38.9438032818323, 118.44653785228729], type: 2, icon: 'interface_yellow', rotationAngle: -58.8, |
|||
info: {berthName: '2泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '2泊位', xy: [38.944215192999486, 118.4459960460663], type: 0, fontSize: 16, tagAnchorType: 3, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.943469565958026, 118.44652175903322], type: 3, icon: 'ship_problem', rotationAngle: 121, reason: 1, status: 3, |
|||
info: {shipName: '东成山', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '东成山', xy: [38.94355597905776, 118.44614624977113], type: 0, fontSize: 16, tagAnchorType: 2, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94322219750925, 118.4463930130005], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
} |
|||
] |
|||
}, |
|||
// ]},
|
|||
|
|||
|
|||
// {xy: [38.94499956615951, 118.44398975372316], type: 1, icon: 'shorepower_blue', rotationAngle: 0,
|
|||
// info: {name: '3号岸电设备', installedPower: '2000千伏安', voltage: '6/6.6千伏', frequency: '50/60赫兹', interfaceCount: '3', simultaneouslyInterfaceCount: '1'},
|
|||
// parent: {},
|
|||
// tags:[],
|
|||
// icons: [
|
|||
{xy: [38.94521906957387, 118.44356996758943], type: 2, icon: 'interface_green', rotationAngle: -58.8, |
|||
info: {berthName: '3泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '使用中', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '3泊位', xy: [38.94554194678001, 118.44319581985475], type: 0, fontSize: 16, tagAnchorType: 3, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.944909090691475, 118.44343119744725], type: 3, icon: 'ship_green', rotationAngle: 121, reason: 9, status: 1, |
|||
info: {shipName: '华元503', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '2192千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '华元503', xy: [38.94490777825935, 118.44327092170717], type: 0, fontSize: 16, tagAnchorType: 2, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
// ]
|
|||
// },
|
|||
|
|||
|
|||
// {xy: [38.94641391923306, 118.44098567962648], type: 1, icon: 'shorepower_blue', rotationAngle: 0,
|
|||
// info: {name: '4号岸电设备', installedPower: '2000千伏安', voltage: '6/6.6千伏', frequency: '50/60赫兹', interfaceCount: '3', simultaneouslyInterfaceCount: '1'},
|
|||
// parent: {},
|
|||
// tags:[],
|
|||
// icons: [
|
|||
{xy: [38.946586276690354, 118.44064235687257], type: 2, icon: 'interface_red', rotationAngle: -58.8, |
|||
info: {berthName: '4泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '故障/检修', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '4泊位', xy: [38.946910396364125, 118.44033122062685], type: 0, fontSize: 16, tagAnchorType: 3, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.946256745210576, 118.4406477212906], type: 3, icon: 'ship_red', rotationAngle: 121, reason: 6, status: 3, |
|||
info: {shipName: '盛达海', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '盛达海', xy: [38.94629292848092, 118.44037413597108], type: 0, fontSize: 16, tagAnchorType: 2, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94598419252245, 118.44058871269227], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
// ]
|
|||
// },
|
|||
|
|||
|
|||
// {xy: [38.94765719155025, 118.43841075897218], type: 1, icon: 'shorepower_blue', rotationAngle: 0,
|
|||
// info: {name: '5号岸电设备', installedPower: '2000千伏安', voltage: '6/6.6千伏', frequency: '50/60赫兹', interfaceCount: '3', simultaneouslyInterfaceCount: '1'},
|
|||
// parent: {},
|
|||
// tags:[],
|
|||
// icons: [
|
|||
{xy: [38.94783347690156, 118.43805134296419], type: 2, icon: 'interface_yellow', rotationAngle: -58.8, |
|||
info: {berthName: '5泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '5泊位', xy: [38.94819537985111, 118.43771338462831], type: 0, fontSize: 16, tagAnchorType: 3, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.94748309511211, 118.43805134296419], type: 3, icon: 'ship_problem', rotationAngle: 121, reason: 2, status: 3, |
|||
info: {shipName: '浙海温州', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '浙海温州', xy: [38.94756957911453, 118.43769192695619], type: 0, fontSize: 16, tagAnchorType: 2, background: true, parent: {}, tags:[], icons: [],}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94723581646269, 118.43793869018556], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
], |
|||
}, |
|||
] |
|||
}, |
|||
// ]
|
|||
// },
|
|||
] |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
{name: '河北华电曹妃甸储运', xy: [38.98916912512044, 118.45514774322511], type: 0, fontSize: 18, tagAnchorType: 2, background: false, |
|||
parent: {}, |
|||
tags:[], |
|||
icons: [ |
|||
{xy: [38.98171382209705, 118.4525352716446], type: 1, icon: 'shorepower_blue', rotationAngle: 0, ratio: 4, |
|||
info: {name: '1号岸电设备', installedPower: '2000千伏安', voltage: '6/6.6千伏', frequency: '50/60赫兹', interfaceCount: '2', simultaneouslyInterfaceCount: '1'}, |
|||
parent: {}, |
|||
tags:[], |
|||
icons: [ |
|||
{xy: [38.980330557533094, 118.45477223396303], type: 2, icon: 'interface_yellow', rotationAngle: 0, |
|||
info: {berthName: '806泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '806泊位', xy: [38.98052656782281, 118.45470786094667], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], parent: {}, icons: [],}, |
|||
], |
|||
icons:[ |
|||
{xy: [38.980547376325056, 118.45514774322511], type: 3, icon: 'ship_problem', rotationAngle: 0, reason: 5, status: 3, |
|||
info: {shipName: '华海航2', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '华海航2', xy: [38.98067662214458, 118.455308675766], type: 0, fontSize: 16, tagAnchorType: 1, background: true, parent: {}, tags:[], icons: [],}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.941786918944366, 118.44942927360536], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
{xy: [38.98291158299341, 118.45474541187288], type: 2, icon: 'interface_yellow', rotationAngle: 0, |
|||
info: {berthName: '807泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '807泊位', xy: [38.98310332916697, 118.45466494560243], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.983115870390485, 118.45514237880708], type: 3, icon: 'ship_problem', rotationAngle: 0, reason: 7, status: 3, |
|||
info: {shipName: '中茂98', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '中茂98', xy: [38.98322857125241, 118.45531404018404], type: 0, fontSize: 16, tagAnchorType: 1, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94322219750925, 118.4463930130005], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
} |
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
{xy: [38.98820189340982, 118.45261573791505], type: 1, icon: 'shorepower_blue', rotationAngle: 0, ratio: 4, |
|||
info: {name: '2号岸电设备', installedPower: '2000千伏安', voltage: '6/6.6千伏', frequency: '50/60赫兹', interfaceCount: '3', simultaneouslyInterfaceCount: '1'}, |
|||
parent: {}, |
|||
tags:[], |
|||
icons: [ |
|||
{xy: [38.98574299196949, 118.45476893109242], type: 2, icon: 'interface_green', rotationAngle: 0, |
|||
info: {berthName: '808泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '使用中', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '808泊位', xy: [38.98596369669985, 118.45462739467622], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.98548876283165, 118.45513701438905], type: 3, icon: 'ship_green', rotationAngle: 180, reason: 9, status: 1, |
|||
info: {shipName: '永宁2', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '2192千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '永宁2', xy: [38.985901491123464, 118.45530331134798], type: 0, fontSize: 16, tagAnchorType: 1, background: true, tags:[], icons: [], parent: {},}, |
|||
{name: '永宁2', xy: [38.985901491123464, 118.45530331134798], type: 0, fontSize: 16, tagAnchorType: 1, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
{xy: [38.98700208813734, 118.454766869545], type: 2, icon: 'interface_yellow', rotationAngle: 0, |
|||
info: {berthName: '809泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '故障/检修', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '809泊位', xy: [38.987218846204165, 118.4546595811844], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.98722303926324, 118.45514164997102], type: 3, icon: 'ship_problem', rotationAngle: 0, reason: 8, status: 3, |
|||
info: {shipName: '华鲁海1', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '华鲁海1', xy: [38.98731892349952, 118.45531404018404], type: 0, fontSize: 16, tagAnchorType: 1, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94598419252245, 118.44058871269227], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
{xy: [38.991184197811535, 118.454766869545], type: 2, icon: 'interface_green', rotationAngle: 0, |
|||
info: {berthName: '810泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '810泊位', xy: [38.991409041819146, 118.45464885234834], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.990935693058206, 118.45513628555299], type: 3, icon: 'ship_green', rotationAngle: 180, reason: 9, status: 1, |
|||
info: {shipName: '和泰通10', callSign: 'XHHH1', shipCompany:'华能', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '和泰通10', xy: [38.99135791146007, 118.4552925817847], type: 0, fontSize: 16, tagAnchorType: 1, background: true, parent: {}, tags:[], icons: [],}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94723581646269, 118.43793869018556], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
], |
|||
}, |
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
{name: '国投曹妃甸港口', xy: [38.95787372769494, 118.4544610977173], type: 0, fontSize: 18, tagAnchorType: 2, background: false, |
|||
parent: {}, |
|||
tags:[], |
|||
icons: [ |
|||
// {xy: [38.97960116983217, 118.45476150512695], type: 1, icon: 'shorepower_blue', rotationAngle: 0,
|
|||
// info: {name: '1号岸电设备', installedPower: '2000千伏安', voltage: '6/6.6千伏', frequency: '50/60赫兹', interfaceCount: '2', simultaneouslyInterfaceCount: '1'},
|
|||
// parent: {},
|
|||
// tags:[],
|
|||
// icons: [
|
|||
{xy: [38.96404006594963, 118.45477223396303], type: 2, icon: 'interface_yellow', rotationAngle: 0, |
|||
info: {berthName: '201#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '201#泊位', xy: [38.964256852392246, 118.45469713211061], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], parent: {}, icons: [],}, |
|||
], |
|||
icons:[ |
|||
{xy: [38.9642861101337, 118.45515310764314], type: 3, icon: 'ship_problem', rotationAngle: 0, reason: 2, status: 2, |
|||
info: {shipName: '新世纪128', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '新世纪128', xy: [38.96440704679231, 118.4553247690201], type: 0, fontSize: 16, tagAnchorType: 1, background: true, parent: {}, tags:[], icons: [],}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.941786918944366, 118.44942927360536], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
{xy: [38.96133711832845, 118.45479905605318], type: 2, icon: 'interface_yellow', rotationAngle: 0, |
|||
info: {berthName: '202#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '202#泊位', xy: [38.96155397914768, 118.4546595811844], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.96159568307525, 118.4551638364792], type: 3, icon: 'ship_problem', rotationAngle: 0, reason: 7, status: 3, |
|||
info: {shipName: '信洋新征程', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '信洋新征程', xy: [38.96169577240135, 118.4553247690201], type: 0, fontSize: 16, tagAnchorType: 1, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94322219750925, 118.4463930130005], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
} |
|||
] |
|||
}, |
|||
// ]
|
|||
// },
|
|||
|
|||
|
|||
{xy: [38.95564214358565, 118.45195054960143], type: 1, icon: 'shorepower_blue', rotationAngle: 0, ratio: 4, |
|||
info: {name: '3号岸电设备', installedPower: '2000千伏安', voltage: '6/6.6千伏', frequency: '50/60赫兹', interfaceCount: '3', simultaneouslyInterfaceCount: '1'}, |
|||
parent: {}, |
|||
tags:[], |
|||
icons: [ |
|||
{xy: [38.95914310536718, 118.45478733581544], type: 2, icon: 'interface_yellow', rotationAngle: 0, |
|||
info: {berthName: '203#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '使用中', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '203#泊位', xy: [38.95935580237831, 118.45465421676637], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.95937665499213, 118.45516920089723], type: 3, icon: 'ship_problem', rotationAngle: 0, reason: 1, status: 3, |
|||
info: {shipName: '舜华', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '2192千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '舜华', xy: [38.95937665499213, 118.45534086227418], type: 0, fontSize: 16, tagAnchorType: 1, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
{xy: [38.9566666666667, 118.45479], type: 2, icon: 'interface_yellow', rotationAngle: 0, |
|||
info: {berthName: '204#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '故障/检修', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '204#泊位', xy: [38.95688208014856, 118.45465421676637], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.95688625081742, 118.45516701438905], type: 3, icon: 'ship_problem', rotationAngle: 0, reason: 2, status: 3, |
|||
info: {shipName: '安永山', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '安永山', xy: [38.95689876282247, 118.45535159111024], type: 0, fontSize: 16, tagAnchorType: 1, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94598419252245, 118.44058871269227], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
{xy: [38.95382751650487, 118.45478487083635], type: 2, icon: 'interface_yellow', rotationAngle: 1, |
|||
info: {berthName: '205#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '205#泊位', xy: [38.9544906279055, 118.45498144626619], type: 0, fontSize: 16, tagAnchorType: 4, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.95403710840712, 118.45515310764314], type: 3, icon: 'ship_problem', rotationAngle: 1, reason: 3, status: 2, |
|||
info: {shipName: '东亿603', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '东亿603', xy: [38.9540823482338, 118.45533013343812], type: 0, fontSize: 16, tagAnchorType: 1, background: true, parent: {}, tags:[], icons: [],}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94723581646269, 118.43793869018556], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
], |
|||
}, |
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
{xy: [38.94949642639647, 118.45278739789693], type: 1, icon: 'shorepower_blue', rotationAngle: 0, ratio: 4, |
|||
info: {name: '4号岸电设备', installedPower: '2000千伏安', voltage: '6/6.6千伏', frequency: '50/60赫兹', interfaceCount: '3', simultaneouslyInterfaceCount: '1'}, |
|||
parent: {}, |
|||
tags:[], |
|||
icons: [ |
|||
{xy: [38.94920619528106, 118.45447719097139], type: 2, icon: 'interface_yellow', rotationAngle: -58.5, |
|||
info: {berthName: '206#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '使用中', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '206#泊位', xy: [38.94914779956731, 118.4543538093567], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.949429777655, 118.45474004745483], type: 3, icon: 'ship_problem', rotationAngle: 121.5, reason: 7, status: 3, |
|||
info: {shipName: '太行128', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '2192千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '太行128', xy: [38.94948148871223, 118.45495462417604], type: 0, fontSize: 16, tagAnchorType: 3, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
{xy: [38.947992362158175, 118.4570360183716], type: 2, icon: 'interface_yellow', rotationAngle: -58.5, |
|||
info: {berthName: '207#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '故障/检修', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '207#泊位', xy: [38.947929820857425, 118.4569823741913], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.94815255152406, 118.45741152763368], type: 3, icon: 'ship_problem', rotationAngle: 121.5, reason: 1, status: 3, |
|||
info: {shipName: '东疆胜', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '东疆胜', xy: [38.94826768691209, 118.45749735832216], type: 0, fontSize: 16, tagAnchorType: 3, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94598419252245, 118.44058871269227], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
{xy: [38.946444199206084, 118.46030294895174], type: 2, icon: 'interface_yellow', rotationAngle: -58.5, |
|||
info: {berthName: '208#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '208#泊位', xy: [38.946369116068404, 118.46030831336977], type: 0, fontSize: 16, tagAnchorType: 2, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.9466319058961, 118.46060872077943], type: 3, icon: 'ship_problem', rotationAngle: 121.5, reason: 2, status: 3, |
|||
info: {shipName: '东和明16', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '东和明16', xy: [38.946732017163924, 118.46071600914003], type: 0, fontSize: 16, tagAnchorType: 3, background: true, parent: {}, tags:[], icons: [],}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94723581646269, 118.43793869018556], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
], |
|||
}, |
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
{xy: [38.946733887149165, 118.45633864229731], type: 1, icon: 'shorepower_blue', rotationAngle: 0, ratio: 4, |
|||
info: {name: '5号岸电设备', installedPower: '2000千伏安', voltage: '6/6.6千伏', frequency: '50/60赫兹', interfaceCount: '2', simultaneouslyInterfaceCount: '1'}, |
|||
parent: {}, |
|||
tags:[], |
|||
icons: [ |
|||
{xy: [38.944815666282894, 118.4638434648514], type: 2, icon: 'interface_yellow', rotationAngle: -58.5, ratio:0.7, |
|||
info: {berthName: '209#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '209#泊位', xy: [38.944733926653164, 118.46453547477724], type: 0, fontSize: 16, tagAnchorType: 3, background: false, tags:[], parent: {}, icons: [],}, |
|||
], |
|||
icons:[ |
|||
{xy: [38.94517410846952, 118.46366643905641], type: 3, icon: 'ship_problem', rotationAngle: -58.5, reason: 3, status: 2, |
|||
info: {shipName: '华盛151', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '华盛151', xy: [38.945384685350895, 118.46356987953187], type: 0, fontSize: 16, tagAnchorType: 3, background: true, parent: {}, tags:[], icons: [],}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.941786918944366, 118.44942927360536], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
{xy: [38.94463691900152, 118.46389218444597], type: 2, icon: 'interface_red', rotationAngle: -58.5, ratio:0.7, |
|||
info: {berthName: '210#泊位', totalPower: '99999千瓦时', updateTime: '2025-10-31 23:59:59', status: '未使用', InterfaceType: '350A', berthDepth: '10米'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '210#泊位', xy: [38.9449967491522, 118.4628349542618], type: 0, fontSize: 16, tagAnchorType: 4, background: false, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
{xy: [38.94455452597361, 118.46345471881868], type: 3, icon: 'ship_red', rotationAngle: -58.5, reason: 4, status: 3, |
|||
info: {shipName: '华润电力2', callSign: 'XHHH1', shipCompany:'国投', phone: '13333333333', length: '190米', width: '40米', tonnage: '18万吨', type: '运煤船', CommodityName: '煤炭', cargoWeight: '17万吨', |
|||
startUsingTime: '2025-11-01 01:50', scheduledDepartureTime: '2025-11-02 23:30', shorePowerConsumption: '0千瓦时', totalAuxiliaryPower: '1100千瓦'}, |
|||
parent: {}, |
|||
tags:[ |
|||
{name: '华润电力2', xy: [38.94439598327865, 118.46348404884338], type: 0, fontSize: 16, tagAnchorType: 2, background: true, tags:[], icons: [], parent: {},}, |
|||
], |
|||
icons: [ |
|||
// {xy: [38.94322219750925, 118.4463930130005], type: 4, icon: 'problem', rotationAngle: 0, parent: {}, tags:[], icons: [],},
|
|||
] |
|||
} |
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
] |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
{type: 4, color: `rgba(130, 90, 10, 1)`, fillColor: `rgba(199, 187, 132, 1)`, fillOpacity: 1, minZoom: 13, // 华能曹妃甸港-区域坐标
|
|||
xy: [ |
|||
[38.95702275355564, 118.43592166900636], |
|||
[38.95640120226074, 118.43591630458833], |
|||
[38.956217655869274, 118.4363079071045], |
|||
[38.95624685646336, 118.43660831451416], |
|||
[38.95559192596182, 118.43797624111177], |
|||
[38.955400034349886, 118.4380030632019], |
|||
[38.95524151480031, 118.43798696994783], |
|||
[38.955137225429574, 118.43793332576753], |
|||
[38.955095509638305, 118.43791186809541], |
|||
[38.95495367576432, 118.43785285949708], |
|||
[38.95062343440496, 118.43446791172029], |
|||
[38.94917161796837, 118.43751490116121], |
|||
[38.948249615654795, 118.43681752681734], |
|||
[38.94158664520672, 118.45089912414551], |
|||
[38.94206229440991, 118.45126926898958], |
|||
[38.942199981741595, 118.45100104808809], |
|||
[38.94262555907637, 118.45133364200593], |
|||
[38.942266739139505, 118.45206320285799], |
|||
[38.94220832641979, 118.4522992372513], |
|||
[38.942162430677655, 118.45263183116914], |
|||
[38.942254222132206, 118.45551788806917], |
|||
[38.942604697501864, 118.45499217510225], |
|||
[38.94276741762028, 118.45498681068422], |
|||
[38.94303444469763, 118.45517992973329], |
|||
[38.9429676880226, 118.45531940460206], |
|||
[38.945963331936206, 118.45765829086305], |
|||
[38.946017569447626, 118.45756709575654], |
|||
[38.94645146804519, 118.4579372406006], |
|||
], |
|||
}, |
|||
|
|||
{type: 4, color: `rgba(130, 90, 10, 1)`, fillColor: `rgba(199, 187, 132, 1)`, fillOpacity: 1, minZoom: 13, // 国投曹妃甸港-区域坐标
|
|||
xy: [ |
|||
[38.94646398431148, 118.4579372406006], |
|||
[38.9464097471416, 118.45811426639558], |
|||
[38.94590909438329, 118.45916032791139], |
|||
[38.94577558638391, 118.45953583717348], |
|||
[38.94582982403899, 118.45973432064058], |
|||
[38.94633047735712, 118.46012592315675], |
|||
[38.94415678188506, 118.46471250057222], |
|||
[38.94439042605403, 118.46491634845735], |
|||
[38.949897529903765, 118.45332384109498], |
|||
[38.95199178589285, 118.45497071743013], |
|||
[38.95273852754434, 118.45491707324982], |
|||
[38.96562796722419, 118.45494389533998], |
|||
[38.96562796722419, 118.44710111618043], |
|||
[38.97092071810863, 118.43991279602052], |
|||
[38.97109171449716, 118.43591094017029], |
|||
[38.97021170428815, 118.43586266040803], |
|||
[38.96904390134737, 118.4361094236374], |
|||
[38.95702275355564, 118.43590557575227], |
|||
// [],
|
|||
// [],
|
|||
// [],
|
|||
// [],
|
|||
// [],
|
|||
// [],
|
|||
|
|||
] |
|||
}, |
|||
|
|||
|
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.9815766467409, 118.45252454280855], |
|||
[38.98156382800117, 118.4547507762909], |
|||
[38.98032560436857, 118.45476150512695], |
|||
] |
|||
}, |
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.98156382800117, 118.4547507762909], |
|||
[38.982860467266946, 118.45474541187288], |
|||
] |
|||
}, |
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.98820189340982, 118.45261573791505], |
|||
[38.9881646528042, 118.45448255538942], |
|||
[38.9857050495674, 118.45447182655336], |
|||
[38.98570921853932, 118.45477223396303], |
|||
] |
|||
}, |
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.986959899035384, 118.45447182655336], |
|||
[38.98696823683122, 118.45474004745483], |
|||
] |
|||
}, |
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.9881646528042, 118.45448255538942], |
|||
[38.99112033712731, 118.45448255538942], |
|||
[38.991137011737834, 118.45476150512695], |
|||
] |
|||
}, |
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.95564214358565, 118.45195054960143], |
|||
[38.955600451863084, 118.45478296274207], |
|||
[38.95908758754183, 118.45478832627971], |
|||
] |
|||
}, |
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.955600451863084, 118.45478296274207], |
|||
[38.95378953344623, 118.45477759744465], |
|||
] |
|||
}, |
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.949363241777746, 118.4527659410885], |
|||
[38.94936348204682, 118.45412850350844], |
|||
[38.946413737058165, 118.46034586343174], |
|||
] |
|||
}, |
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.94660148813071, 118.45633327914759], |
|||
[38.94658897286304, 118.4578353160253], |
|||
[38.945821269938364, 118.45951974313134], |
|||
[38.94586299313705, 118.45969676891002], |
|||
[38.94636784189484, 118.46008837139007], |
|||
[38.944586252136524, 118.46385955691731], |
|||
] |
|||
}, |
|||
|
|||
{type: 5, color: `rgba(220, 70, 20, 1)`, minZoom: 13, dashArray: [10, 7], weight: 2, |
|||
xy: [ |
|||
[38.94542489832619, 118.46209466354823], |
|||
[38.94557510256635, 118.46220731631647], |
|||
[38.944794871518646, 118.46387565016992], |
|||
] |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
] |
|||
|
|||
export default tagsData ; |
|||
File diff suppressed because it is too large
@ -0,0 +1,57 @@ |
|||
<script lang="ts" setup> |
|||
import { isDark } from '@/utils/is' |
|||
import { useAppStore } from '@/store/modules/app' |
|||
import { useDesign } from '@/hooks/web/useDesign' |
|||
import { CACHE_KEY, useCache } from '@/hooks/web/useCache' |
|||
import routerSearch from '@/components/RouterSearch/index.vue' |
|||
|
|||
defineOptions({ name: 'APP' }) |
|||
|
|||
const { getPrefixCls } = useDesign() |
|||
const prefixCls = getPrefixCls('app') |
|||
const appStore = useAppStore() |
|||
const currentSize = computed(() => appStore.getCurrentSize) |
|||
const greyMode = computed(() => appStore.getGreyMode) |
|||
const { wsCache } = useCache() |
|||
|
|||
// 根据浏览器当前主题设置系统主题色 |
|||
const setDefaultTheme = () => { |
|||
let isDarkTheme = wsCache.get(CACHE_KEY.IS_DARK) |
|||
if (isDarkTheme === null) { |
|||
isDarkTheme = isDark() |
|||
} |
|||
appStore.setIsDark(isDarkTheme) |
|||
} |
|||
setDefaultTheme() |
|||
</script> |
|||
<template> |
|||
<ConfigGlobal :size="currentSize"> |
|||
<RouterView :class="greyMode ? `${prefixCls}-grey-mode` : ''" /> |
|||
<routerSearch /> |
|||
</ConfigGlobal> |
|||
</template> |
|||
<style lang="scss"> |
|||
$prefix-cls: #{$namespace}-app; |
|||
|
|||
.size { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
html, |
|||
body { |
|||
@extend .size; |
|||
|
|||
padding: 0 !important; |
|||
margin: 0; |
|||
overflow: hidden; |
|||
|
|||
#app { |
|||
@extend .size; |
|||
} |
|||
} |
|||
|
|||
.#{$prefix-cls}-grey-mode { |
|||
filter: grayscale(100%); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,65 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI 聊天对话 VO
|
|||
export interface ChatConversationVO { |
|||
id: number // ID 编号
|
|||
userId: number // 用户编号
|
|||
title: string // 对话标题
|
|||
pinned: boolean // 是否置顶
|
|||
roleId: number // 角色编号
|
|||
modelId: number // 模型编号
|
|||
model: string // 模型标志
|
|||
temperature: number // 温度参数
|
|||
maxTokens: number // 单条回复的最大 Token 数量
|
|||
maxContexts: number // 上下文的最大 Message 数量
|
|||
createTime?: Date // 创建时间
|
|||
// 额外字段
|
|||
systemMessage?: string // 角色设定
|
|||
modelName?: string // 模型名字
|
|||
roleAvatar?: string // 角色头像
|
|||
modelMaxTokens?: string // 模型的单条回复的最大 Token 数量
|
|||
modelMaxContexts?: string // 模型的上下文的最大 Message 数量
|
|||
} |
|||
|
|||
// AI 聊天对话 API
|
|||
export const ChatConversationApi = { |
|||
// 获得【我的】聊天对话
|
|||
getChatConversationMy: async (id: number) => { |
|||
return await request.get({ url: `/ai/chat/conversation/get-my?id=${id}` }) |
|||
}, |
|||
|
|||
// 新增【我的】聊天对话
|
|||
createChatConversationMy: async (data?: ChatConversationVO) => { |
|||
return await request.post({ url: `/ai/chat/conversation/create-my`, data }) |
|||
}, |
|||
|
|||
// 更新【我的】聊天对话
|
|||
updateChatConversationMy: async (data: ChatConversationVO) => { |
|||
return await request.put({ url: `/ai/chat/conversation/update-my`, data }) |
|||
}, |
|||
|
|||
// 删除【我的】聊天对话
|
|||
deleteChatConversationMy: async (id: string) => { |
|||
return await request.delete({ url: `/ai/chat/conversation/delete-my?id=${id}` }) |
|||
}, |
|||
|
|||
// 删除【我的】所有对话,置顶除外
|
|||
deleteChatConversationMyByUnpinned: async () => { |
|||
return await request.delete({ url: `/ai/chat/conversation/delete-by-unpinned` }) |
|||
}, |
|||
|
|||
// 获得【我的】聊天对话列表
|
|||
getChatConversationMyList: async () => { |
|||
return await request.get({ url: `/ai/chat/conversation/my-list` }) |
|||
}, |
|||
|
|||
// 获得对话分页
|
|||
getChatConversationPage: async (params: any) => { |
|||
return await request.get({ url: `/ai/chat/conversation/page`, params }) |
|||
}, |
|||
|
|||
// 管理员删除消息
|
|||
deleteChatConversationByAdmin: async (id: number) => { |
|||
return await request.delete({ url: `/ai/chat/conversation/delete-by-admin?id=${id}` }) |
|||
} |
|||
} |
|||
@ -0,0 +1,104 @@ |
|||
import request from '@/config/axios' |
|||
import { fetchEventSource } from '@microsoft/fetch-event-source' |
|||
import { getAccessToken } from '@/utils/auth' |
|||
import { config } from '@/config/axios/config' |
|||
|
|||
// 聊天VO
|
|||
export interface ChatMessageVO { |
|||
id: number // 编号
|
|||
conversationId: number // 对话编号
|
|||
type: string // 消息类型
|
|||
userId: string // 用户编号
|
|||
roleId: string // 角色编号
|
|||
model: number // 模型标志
|
|||
modelId: number // 模型编号
|
|||
content: string // 聊天内容
|
|||
reasoningContent?: string // 推理内容
|
|||
attachmentUrls?: string[] // 附件 URL 数组
|
|||
tokens: number // 消耗 Token 数量
|
|||
segmentIds?: number[] // 段落编号
|
|||
segments?: { |
|||
id: number // 段落编号
|
|||
content: string // 段落内容
|
|||
documentId: number // 文档编号
|
|||
documentName: string // 文档名称
|
|||
}[] |
|||
webSearchPages?: { |
|||
name: string // 名称
|
|||
icon: string // 图标
|
|||
title: string // 标题
|
|||
url: string // URL
|
|||
snippet: string // 内容的简短描述
|
|||
summary: string // 内容的文本摘要
|
|||
}[] |
|||
createTime: Date // 创建时间
|
|||
roleAvatar: string // 角色头像
|
|||
userAvatar: string // 用户头像
|
|||
} |
|||
|
|||
// AI chat 聊天
|
|||
export const ChatMessageApi = { |
|||
// 消息列表
|
|||
getChatMessageListByConversationId: async (conversationId: number | null) => { |
|||
return await request.get({ |
|||
url: `/ai/chat/message/list-by-conversation-id?conversationId=${conversationId}` |
|||
}) |
|||
}, |
|||
|
|||
// 发送 Stream 消息
|
|||
// 为什么不用 axios 呢?因为它不支持 SSE 调用
|
|||
sendChatMessageStream: async ( |
|||
conversationId: number, |
|||
content: string, |
|||
ctrl, |
|||
enableContext: boolean, |
|||
enableWebSearch: boolean, |
|||
onMessage, |
|||
onError, |
|||
onClose, |
|||
attachmentUrls?: string[] |
|||
) => { |
|||
const token = getAccessToken() |
|||
return fetchEventSource(`${config.base_url}/ai/chat/message/send-stream`, { |
|||
method: 'post', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
Authorization: `Bearer ${token}` |
|||
}, |
|||
openWhenHidden: true, |
|||
body: JSON.stringify({ |
|||
conversationId, |
|||
content, |
|||
useContext: enableContext, |
|||
useSearch: enableWebSearch, |
|||
attachmentUrls: attachmentUrls || [] |
|||
}), |
|||
onmessage: onMessage, |
|||
onerror: onError, |
|||
onclose: onClose, |
|||
signal: ctrl.signal |
|||
}) |
|||
}, |
|||
|
|||
// 删除消息
|
|||
deleteChatMessage: async (id: string) => { |
|||
return await request.delete({ url: `/ai/chat/message/delete?id=${id}` }) |
|||
}, |
|||
|
|||
// 删除指定对话的消息
|
|||
deleteByConversationId: async (conversationId: number) => { |
|||
return await request.delete({ |
|||
url: `/ai/chat/message/delete-by-conversation-id?conversationId=${conversationId}` |
|||
}) |
|||
}, |
|||
|
|||
// 获得消息分页
|
|||
getChatMessagePage: async (params: any) => { |
|||
return await request.get({ url: '/ai/chat/message/page', params }) |
|||
}, |
|||
|
|||
// 管理员删除消息
|
|||
deleteChatMessageByAdmin: async (id: number) => { |
|||
return await request.delete({ url: `/ai/chat/message/delete-by-admin?id=${id}` }) |
|||
} |
|||
} |
|||
@ -0,0 +1,102 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI 绘图 VO
|
|||
export interface ImageVO { |
|||
id: number // 编号
|
|||
platform: string // 平台
|
|||
model: string // 模型
|
|||
prompt: string // 提示词
|
|||
width: number // 图片宽度
|
|||
height: number // 图片高度
|
|||
status: number // 状态
|
|||
publicStatus: boolean // 公开状态
|
|||
picUrl: string // 任务地址
|
|||
errorMessage: string // 错误信息
|
|||
options: any // 配置 Map<string, string>
|
|||
taskId: number // 任务编号
|
|||
buttons: ImageMidjourneyButtonsVO[] // mj 操作按钮
|
|||
createTime: Date // 创建时间
|
|||
finishTime: Date // 完成时间
|
|||
} |
|||
|
|||
export interface ImageDrawReqVO { |
|||
prompt: string // 提示词
|
|||
modelId: number // 模型
|
|||
style: string // 图像生成的风格
|
|||
width: string // 图片宽度
|
|||
height: string // 图片高度
|
|||
options: object // 绘制参数,Map<String, String>
|
|||
} |
|||
|
|||
export interface ImageMidjourneyImagineReqVO { |
|||
prompt: string // 提示词
|
|||
modelId: number // 模型
|
|||
base64Array: string[] // size不能为空
|
|||
width: string // 图片宽度
|
|||
height: string // 图片高度
|
|||
version: string // 版本
|
|||
} |
|||
|
|||
export interface ImageMidjourneyActionVO { |
|||
id: number // 图片编号
|
|||
customId: string // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识
|
|||
} |
|||
|
|||
export interface ImageMidjourneyButtonsVO { |
|||
customId: string // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识
|
|||
emoji: string // 图标 emoji
|
|||
label: string // Make Variations 文本
|
|||
style: number // 样式: 2(Primary)、3(Green)
|
|||
} |
|||
|
|||
// AI 图片 API
|
|||
export const ImageApi = { |
|||
// 获取【我的】绘图分页
|
|||
getImagePageMy: async (params: any) => { |
|||
return await request.get({ url: `/ai/image/my-page`, params }) |
|||
}, |
|||
// 获取【我的】绘图记录
|
|||
getImageMy: async (id: number) => { |
|||
return await request.get({ url: `/ai/image/get-my?id=${id}` }) |
|||
}, |
|||
// 获取【我的】绘图记录列表
|
|||
getImageListMyByIds: async (ids: number[]) => { |
|||
return await request.get({ url: `/ai/image/my-list-by-ids`, params: { ids: ids.join(',') } }) |
|||
}, |
|||
// 生成图片
|
|||
drawImage: async (data: ImageDrawReqVO) => { |
|||
return await request.post({ url: `/ai/image/draw`, data }) |
|||
}, |
|||
// 删除【我的】绘画记录
|
|||
deleteImageMy: async (id: number) => { |
|||
return await request.delete({ url: `/ai/image/delete-my?id=${id}` }) |
|||
}, |
|||
|
|||
// ================ midjourney 专属 ================
|
|||
|
|||
// 【Midjourney】生成图片
|
|||
midjourneyImagine: async (data: ImageMidjourneyImagineReqVO) => { |
|||
return await request.post({ url: `/ai/image/midjourney/imagine`, data }) |
|||
}, |
|||
// 【Midjourney】Action 操作(二次生成图片)
|
|||
midjourneyAction: async (data: ImageMidjourneyActionVO) => { |
|||
return await request.post({ url: `/ai/image/midjourney/action`, data }) |
|||
}, |
|||
|
|||
// ================ 绘图管理 ================
|
|||
|
|||
// 查询绘画分页
|
|||
getImagePage: async (params: any) => { |
|||
return await request.get({ url: `/ai/image/page`, params }) |
|||
}, |
|||
|
|||
// 更新绘画发布状态
|
|||
updateImage: async (data: any) => { |
|||
return await request.put({ url: '/ai/image/update', data }) |
|||
}, |
|||
|
|||
// 删除绘画
|
|||
deleteImage: async (id: number) => { |
|||
return await request.delete({ url: `/ai/image/delete?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI 知识库文档 VO
|
|||
export interface KnowledgeDocumentVO { |
|||
id: number // 编号
|
|||
knowledgeId: number // 知识库编号
|
|||
name: string // 文档名称
|
|||
contentLength: number // 字符数
|
|||
tokens: number // token 数
|
|||
segmentMaxTokens: number // 分片最大 token 数
|
|||
retrievalCount: number // 召回次数
|
|||
status: number // 是否启用
|
|||
} |
|||
|
|||
// AI 知识库文档 API
|
|||
export const KnowledgeDocumentApi = { |
|||
// 查询知识库文档分页
|
|||
getKnowledgeDocumentPage: async (params: any) => { |
|||
return await request.get({ url: `/ai/knowledge/document/page`, params }) |
|||
}, |
|||
|
|||
// 查询知识库文档详情
|
|||
getKnowledgeDocument: async (id: number) => { |
|||
return await request.get({ url: `/ai/knowledge/document/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增知识库文档(单个)
|
|||
createKnowledgeDocument: async (data: any) => { |
|||
return await request.post({ url: `/ai/knowledge/document/create`, data }) |
|||
}, |
|||
|
|||
// 新增知识库文档(多个)
|
|||
createKnowledgeDocumentList: async (data: any) => { |
|||
return await request.post({ url: `/ai/knowledge/document/create-list`, data }) |
|||
}, |
|||
|
|||
// 修改知识库文档
|
|||
updateKnowledgeDocument: async (data: any) => { |
|||
return await request.put({ url: `/ai/knowledge/document/update`, data }) |
|||
}, |
|||
|
|||
// 修改知识库文档状态
|
|||
updateKnowledgeDocumentStatus: async (data: any) => { |
|||
return await request.put({ |
|||
url: `/ai/knowledge/document/update-status`, |
|||
data |
|||
}) |
|||
}, |
|||
|
|||
// 删除知识库文档
|
|||
deleteKnowledgeDocument: async (id: number) => { |
|||
return await request.delete({ url: `/ai/knowledge/document/delete?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI 知识库 VO
|
|||
export interface KnowledgeVO { |
|||
id: number // 编号
|
|||
name: string // 知识库名称
|
|||
description: string // 知识库描述
|
|||
embeddingModelId: number // 嵌入模型编号,高质量模式时维护
|
|||
topK: number // topK
|
|||
similarityThreshold: number // 相似度阈值
|
|||
} |
|||
|
|||
// AI 知识库 API
|
|||
export const KnowledgeApi = { |
|||
// 查询知识库分页
|
|||
getKnowledgePage: async (params: any) => { |
|||
return await request.get({ url: `/ai/knowledge/page`, params }) |
|||
}, |
|||
|
|||
// 查询知识库详情
|
|||
getKnowledge: async (id: number) => { |
|||
return await request.get({ url: `/ai/knowledge/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增知识库
|
|||
createKnowledge: async (data: KnowledgeVO) => { |
|||
return await request.post({ url: `/ai/knowledge/create`, data }) |
|||
}, |
|||
|
|||
// 修改知识库
|
|||
updateKnowledge: async (data: KnowledgeVO) => { |
|||
return await request.put({ url: `/ai/knowledge/update`, data }) |
|||
}, |
|||
|
|||
// 删除知识库
|
|||
deleteKnowledge: async (id: number) => { |
|||
return await request.delete({ url: `/ai/knowledge/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 获取知识库简单列表
|
|||
getSimpleKnowledgeList: async () => { |
|||
return await request.get({ url: `/ai/knowledge/simple-list` }) |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI 知识库分段 VO
|
|||
export interface KnowledgeSegmentVO { |
|||
id: number // 编号
|
|||
documentId: number // 文档编号
|
|||
knowledgeId: number // 知识库编号
|
|||
vectorId: string // 向量库编号
|
|||
content: string // 切片内容
|
|||
contentLength: number // 切片内容长度
|
|||
tokens: number // token 数量
|
|||
retrievalCount: number // 召回次数
|
|||
status: number // 文档状态
|
|||
createTime: number // 创建时间
|
|||
} |
|||
|
|||
// AI 知识库分段 API
|
|||
export const KnowledgeSegmentApi = { |
|||
// 查询知识库分段分页
|
|||
getKnowledgeSegmentPage: async (params: any) => { |
|||
return await request.get({ url: `/ai/knowledge/segment/page`, params }) |
|||
}, |
|||
|
|||
// 查询知识库分段详情
|
|||
getKnowledgeSegment: async (id: number) => { |
|||
return await request.get({ url: `/ai/knowledge/segment/get?id=` + id }) |
|||
}, |
|||
|
|||
// 删除知识库分段
|
|||
deleteKnowledgeSegment: async (id: number) => { |
|||
return await request.delete({ url: `/ai/knowledge/segment/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 新增知识库分段
|
|||
createKnowledgeSegment: async (data: KnowledgeSegmentVO) => { |
|||
return await request.post({ url: `/ai/knowledge/segment/create`, data }) |
|||
}, |
|||
|
|||
// 修改知识库分段
|
|||
updateKnowledgeSegment: async (data: KnowledgeSegmentVO) => { |
|||
return await request.put({ url: `/ai/knowledge/segment/update`, data }) |
|||
}, |
|||
|
|||
// 修改知识库分段状态
|
|||
updateKnowledgeSegmentStatus: async (data: any) => { |
|||
return await request.put({ |
|||
url: `/ai/knowledge/segment/update-status`, |
|||
data |
|||
}) |
|||
}, |
|||
|
|||
// 切片内容
|
|||
splitContent: async (url: string, segmentMaxTokens: number) => { |
|||
return await request.get({ |
|||
url: `/ai/knowledge/segment/split`, |
|||
params: { url, segmentMaxTokens } |
|||
}) |
|||
}, |
|||
|
|||
// 获取文档处理列表
|
|||
getKnowledgeSegmentProcessList: async (documentIds: number[]) => { |
|||
return await request.get({ |
|||
url: `/ai/knowledge/segment/get-process-list`, |
|||
params: { documentIds: documentIds.join(',') } |
|||
}) |
|||
}, |
|||
|
|||
// 搜索知识库分段
|
|||
searchKnowledgeSegment: async (params: any) => { |
|||
return await request.get({ |
|||
url: `/ai/knowledge/segment/search`, |
|||
params |
|||
}) |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
import { getAccessToken } from '@/utils/auth' |
|||
import { fetchEventSource } from '@microsoft/fetch-event-source' |
|||
import { config } from '@/config/axios/config' |
|||
import request from '@/config/axios' // AI 思维导图 VO
|
|||
|
|||
// AI 思维导图 VO
|
|||
export interface MindMapVO { |
|||
id: number // 编号
|
|||
userId: number // 用户编号
|
|||
prompt: string // 生成内容提示
|
|||
generatedContent: string // 生成的思维导图内容
|
|||
platform: string // 平台
|
|||
model: string // 模型
|
|||
errorMessage: string // 错误信息
|
|||
} |
|||
|
|||
// AI 思维导图生成 VO
|
|||
export interface AiMindMapGenerateReqVO { |
|||
prompt: string |
|||
} |
|||
|
|||
export const AiMindMapApi = { |
|||
generateMindMap: ({ |
|||
data, |
|||
onClose, |
|||
onMessage, |
|||
onError, |
|||
ctrl |
|||
}: { |
|||
data: AiMindMapGenerateReqVO |
|||
onMessage?: (res: any) => void |
|||
onError?: (...args: any[]) => void |
|||
onClose?: (...args: any[]) => void |
|||
ctrl: AbortController |
|||
}) => { |
|||
const token = getAccessToken() |
|||
return fetchEventSource(`${config.base_url}/ai/mind-map/generate-stream`, { |
|||
method: 'post', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
Authorization: `Bearer ${token}` |
|||
}, |
|||
openWhenHidden: true, |
|||
body: JSON.stringify(data), |
|||
onmessage: onMessage, |
|||
onerror: onError, |
|||
onclose: onClose, |
|||
signal: ctrl.signal |
|||
}) |
|||
}, |
|||
|
|||
// 查询思维导图分页
|
|||
getMindMapPage: async (params: any) => { |
|||
return await request.get({ url: `/ai/mind-map/page`, params }) |
|||
}, |
|||
// 删除思维导图
|
|||
deleteMindMap: async (id: number) => { |
|||
return await request.delete({ url: `/ai/mind-map/delete?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI API 密钥 VO
|
|||
export interface ApiKeyVO { |
|||
id: number // 编号
|
|||
name: string // 名称
|
|||
apiKey: string // 密钥
|
|||
platform: string // 平台
|
|||
url: string // 自定义 API 地址
|
|||
status: number // 状态
|
|||
} |
|||
|
|||
// AI API 密钥 API
|
|||
export const ApiKeyApi = { |
|||
// 查询 API 密钥分页
|
|||
getApiKeyPage: async (params: any) => { |
|||
return await request.get({ url: `/ai/api-key/page`, params }) |
|||
}, |
|||
|
|||
// 获得 API 密钥列表
|
|||
getApiKeySimpleList: async () => { |
|||
return await request.get({ url: `/ai/api-key/simple-list` }) |
|||
}, |
|||
|
|||
// 查询 API 密钥详情
|
|||
getApiKey: async (id: number) => { |
|||
return await request.get({ url: `/ai/api-key/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增 API 密钥
|
|||
createApiKey: async (data: ApiKeyVO) => { |
|||
return await request.post({ url: `/ai/api-key/create`, data }) |
|||
}, |
|||
|
|||
// 修改 API 密钥
|
|||
updateApiKey: async (data: ApiKeyVO) => { |
|||
return await request.put({ url: `/ai/api-key/update`, data }) |
|||
}, |
|||
|
|||
// 删除 API 密钥
|
|||
deleteApiKey: async (id: number) => { |
|||
return await request.delete({ url: `/ai/api-key/delete?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI 聊天角色 VO
|
|||
export interface ChatRoleVO { |
|||
id: number // 角色编号
|
|||
modelId: number // 模型编号
|
|||
name: string // 角色名称
|
|||
avatar: string // 角色头像
|
|||
category: string // 角色类别
|
|||
sort: number // 角色排序
|
|||
description: string // 角色描述
|
|||
systemMessage: string // 角色设定
|
|||
welcomeMessage: string // 角色设定
|
|||
publicStatus: boolean // 是否公开
|
|||
status: number // 状态
|
|||
knowledgeIds?: number[] // 引用的知识库 ID 列表
|
|||
toolIds?: number[] // 引用的工具 ID 列表
|
|||
mcpClientNames?: string[] // 引用的 MCP Client 名字列表
|
|||
} |
|||
|
|||
// AI 聊天角色 分页请求 vo
|
|||
export interface ChatRolePageReqVO { |
|||
name?: string // 角色名称
|
|||
category?: string // 角色类别
|
|||
publicStatus: boolean // 是否公开
|
|||
pageNo: number // 是否公开
|
|||
pageSize: number // 是否公开
|
|||
} |
|||
|
|||
// AI 聊天角色 API
|
|||
export const ChatRoleApi = { |
|||
// 查询聊天角色分页
|
|||
getChatRolePage: async (params: any) => { |
|||
return await request.get({ url: `/ai/chat-role/page`, params }) |
|||
}, |
|||
|
|||
// 查询聊天角色详情
|
|||
getChatRole: async (id: number) => { |
|||
return await request.get({ url: `/ai/chat-role/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增聊天角色
|
|||
createChatRole: async (data: ChatRoleVO) => { |
|||
return await request.post({ url: `/ai/chat-role/create`, data }) |
|||
}, |
|||
|
|||
// 修改聊天角色
|
|||
updateChatRole: async (data: ChatRoleVO) => { |
|||
return await request.put({ url: `/ai/chat-role/update`, data }) |
|||
}, |
|||
|
|||
// 删除聊天角色
|
|||
deleteChatRole: async (id: number) => { |
|||
return await request.delete({ url: `/ai/chat-role/delete?id=` + id }) |
|||
}, |
|||
|
|||
// ======= chat 聊天
|
|||
|
|||
// 获取 my role
|
|||
getMyPage: async (params: ChatRolePageReqVO) => { |
|||
return await request.get({ url: `/ai/chat-role/my-page`, params }) |
|||
}, |
|||
|
|||
// 获取角色分类
|
|||
getCategoryList: async () => { |
|||
return await request.get({ url: `/ai/chat-role/category-list` }) |
|||
}, |
|||
|
|||
// 创建角色
|
|||
createMy: async (data: ChatRoleVO) => { |
|||
return await request.post({ url: `/ai/chat-role/create-my`, data }) |
|||
}, |
|||
|
|||
// 更新角色
|
|||
updateMy: async (data: ChatRoleVO) => { |
|||
return await request.put({ url: `/ai/chat-role/update-my`, data }) |
|||
}, |
|||
|
|||
// 删除角色 my
|
|||
deleteMy: async (id: number) => { |
|||
return await request.delete({ url: `/ai/chat-role/delete-my?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI 模型 VO
|
|||
export interface ModelVO { |
|||
id: number // 编号
|
|||
keyId: number // API 秘钥编号
|
|||
name: string // 模型名字
|
|||
model: string // 模型标识
|
|||
platform: string // 模型平台
|
|||
type: number // 模型类型
|
|||
sort: number // 排序
|
|||
status: number // 状态
|
|||
temperature?: number // 温度参数
|
|||
maxTokens?: number // 单条回复的最大 Token 数量
|
|||
maxContexts?: number // 上下文的最大 Message 数量
|
|||
} |
|||
|
|||
// AI 模型 API
|
|||
export const ModelApi = { |
|||
// 查询模型分页
|
|||
getModelPage: async (params: any) => { |
|||
return await request.get({ url: `/ai/model/page`, params }) |
|||
}, |
|||
|
|||
// 获得模型列表
|
|||
getModelSimpleList: async (type?: number) => { |
|||
return await request.get({ |
|||
url: `/ai/model/simple-list`, |
|||
params: { |
|||
type |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 查询模型详情
|
|||
getModel: async (id: number) => { |
|||
return await request.get({ url: `/ai/model/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增模型
|
|||
createModel: async (data: ModelVO) => { |
|||
return await request.post({ url: `/ai/model/create`, data }) |
|||
}, |
|||
|
|||
// 修改模型
|
|||
updateModel: async (data: ModelVO) => { |
|||
return await request.put({ url: `/ai/model/update`, data }) |
|||
}, |
|||
|
|||
// 删除模型
|
|||
deleteModel: async (id: number) => { |
|||
return await request.delete({ url: `/ai/model/delete?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI 工具 VO
|
|||
export interface ToolVO { |
|||
id: number // 工具编号
|
|||
name: string // 工具名称
|
|||
description: string // 工具描述
|
|||
status: number // 状态
|
|||
} |
|||
|
|||
// AI 工具 API
|
|||
export const ToolApi = { |
|||
// 查询工具分页
|
|||
getToolPage: async (params: any) => { |
|||
return await request.get({ url: `/ai/tool/page`, params }) |
|||
}, |
|||
|
|||
// 查询工具详情
|
|||
getTool: async (id: number) => { |
|||
return await request.get({ url: `/ai/tool/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增工具
|
|||
createTool: async (data: ToolVO) => { |
|||
return await request.post({ url: `/ai/tool/create`, data }) |
|||
}, |
|||
|
|||
// 修改工具
|
|||
updateTool: async (data: ToolVO) => { |
|||
return await request.put({ url: `/ai/tool/update`, data }) |
|||
}, |
|||
|
|||
// 删除工具
|
|||
deleteTool: async (id: number) => { |
|||
return await request.delete({ url: `/ai/tool/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 获取工具简单列表
|
|||
getToolSimpleList: async () => { |
|||
return await request.get({ url: `/ai/tool/simple-list` }) |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// AI 音乐 VO
|
|||
export interface MusicVO { |
|||
id: number // 编号
|
|||
userId: number // 用户编号
|
|||
title: string // 音乐名称
|
|||
lyric: string // 歌词
|
|||
imageUrl: string // 图片地址
|
|||
audioUrl: string // 音频地址
|
|||
videoUrl: string // 视频地址
|
|||
status: number // 音乐状态
|
|||
gptDescriptionPrompt: string // 描述词
|
|||
prompt: string // 提示词
|
|||
platform: string // 模型平台
|
|||
model: string // 模型
|
|||
generateMode: number // 生成模式
|
|||
tags: string // 音乐风格标签
|
|||
duration: number // 音乐时长
|
|||
publicStatus: boolean // 是否发布
|
|||
taskId: string // 任务id
|
|||
errorMessage: string // 错误信息
|
|||
} |
|||
|
|||
// AI 音乐 API
|
|||
export const MusicApi = { |
|||
// 查询音乐分页
|
|||
getMusicPage: async (params: any) => { |
|||
return await request.get({ url: `/ai/music/page`, params }) |
|||
}, |
|||
|
|||
// 更新音乐
|
|||
updateMusic: async (data: any) => { |
|||
return await request.put({ url: '/ai/music/update', data }) |
|||
}, |
|||
|
|||
// 删除音乐
|
|||
deleteMusic: async (id: number) => { |
|||
return await request.delete({ url: `/ai/music/delete?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export const getWorkflowPage = async (params) => { |
|||
return await request.get({ url: '/ai/workflow/page', params }) |
|||
} |
|||
|
|||
export const getWorkflow = async (id) => { |
|||
return await request.get({ url: '/ai/workflow/get?id=' + id }) |
|||
} |
|||
|
|||
export const createWorkflow = async (data) => { |
|||
return await request.post({ url: '/ai/workflow/create', data }) |
|||
} |
|||
|
|||
export const updateWorkflow = async (data) => { |
|||
return await request.put({ url: '/ai/workflow/update', data }) |
|||
} |
|||
|
|||
export const deleteWorkflow = async (id) => { |
|||
return await request.delete({ url: '/ai/workflow/delete?id=' + id }) |
|||
} |
|||
|
|||
export const testWorkflow = async (data) => { |
|||
return await request.post({ url: '/ai/workflow/test', data }) |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
import { fetchEventSource } from '@microsoft/fetch-event-source' |
|||
|
|||
import { getAccessToken } from '@/utils/auth' |
|||
import { config } from '@/config/axios/config' |
|||
import { AiWriteTypeEnum } from '@/views/ai/utils/constants' |
|||
import request from '@/config/axios' |
|||
|
|||
export interface WriteVO { |
|||
type: AiWriteTypeEnum.WRITING | AiWriteTypeEnum.REPLY // 1:撰写 2:回复
|
|||
prompt: string // 写作内容提示 1。撰写 2回复
|
|||
originalContent: string // 原文
|
|||
length: number // 长度
|
|||
format: number // 格式
|
|||
tone: number // 语气
|
|||
language: number // 语言
|
|||
userId?: number // 用户编号
|
|||
platform?: string // 平台
|
|||
model?: string // 模型
|
|||
generatedContent?: string // 生成的内容
|
|||
errorMessage?: string // 错误信息
|
|||
createTime?: Date // 创建时间
|
|||
} |
|||
|
|||
export interface AiWritePageReqVO extends PageParam { |
|||
userId?: number // 用户编号
|
|||
type?: AiWriteTypeEnum // 写作类型
|
|||
platform?: string // 平台
|
|||
createTime?: [string, string] // 创建时间
|
|||
} |
|||
|
|||
export interface AiWriteRespVo { |
|||
id: number |
|||
userId: number |
|||
type: number |
|||
platform: string |
|||
model: string |
|||
prompt: string |
|||
generatedContent: string |
|||
originalContent: string |
|||
length: number |
|||
format: number |
|||
tone: number |
|||
language: number |
|||
errorMessage: string |
|||
createTime: string |
|||
} |
|||
|
|||
export const WriteApi = { |
|||
writeStream: ({ |
|||
data, |
|||
onClose, |
|||
onMessage, |
|||
onError, |
|||
ctrl |
|||
}: { |
|||
data: WriteVO |
|||
onMessage?: (res: any) => void |
|||
onError?: (...args: any[]) => void |
|||
onClose?: (...args: any[]) => void |
|||
ctrl: AbortController |
|||
}) => { |
|||
const token = getAccessToken() |
|||
return fetchEventSource(`${config.base_url}/ai/write/generate-stream`, { |
|||
method: 'post', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
Authorization: `Bearer ${token}` |
|||
}, |
|||
openWhenHidden: true, |
|||
body: JSON.stringify(data), |
|||
onmessage: onMessage, |
|||
onerror: onError, |
|||
onclose: onClose, |
|||
signal: ctrl.signal |
|||
}) |
|||
}, |
|||
// 获取写作列表
|
|||
getWritePage: (params: AiWritePageReqVO) => { |
|||
return request.get<PageResult<AiWriteRespVo[]>>({ url: `/ai/write/page`, params }) |
|||
}, |
|||
// 删除写作
|
|||
deleteWrite(id: number) { |
|||
return request.delete({ url: `/ai/write/delete`, params: { id } }) |
|||
} |
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// BPM 流程分类 VO
|
|||
export interface CategoryVO { |
|||
id: number // 分类编号
|
|||
name: string // 分类名
|
|||
code: string // 分类标志
|
|||
status: number // 分类状态
|
|||
sort: number // 分类排序
|
|||
} |
|||
|
|||
// BPM 流程分类 API
|
|||
export const CategoryApi = { |
|||
// 查询流程分类分页
|
|||
getCategoryPage: async (params: any) => { |
|||
return await request.get({ url: `/bpm/category/page`, params }) |
|||
}, |
|||
|
|||
// 查询流程分类列表
|
|||
getCategorySimpleList: async () => { |
|||
return await request.get({ url: `/bpm/category/simple-list` }) |
|||
}, |
|||
|
|||
// 查询流程分类详情
|
|||
getCategory: async (id: number) => { |
|||
return await request.get({ url: `/bpm/category/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增流程分类
|
|||
createCategory: async (data: CategoryVO) => { |
|||
return await request.post({ url: `/bpm/category/create`, data }) |
|||
}, |
|||
|
|||
// 修改流程分类
|
|||
updateCategory: async (data: CategoryVO) => { |
|||
return await request.put({ url: `/bpm/category/update`, data }) |
|||
}, |
|||
|
|||
// 批量修改流程分类的排序
|
|||
updateCategorySortBatch: async (ids: number[]) => { |
|||
return await request.put({ |
|||
url: `/bpm/category/update-sort-batch`, |
|||
params: { |
|||
ids: ids.join(',') |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 删除流程分类
|
|||
deleteCategory: async (id: number) => { |
|||
return await request.delete({ url: `/bpm/category/delete?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export const getProcessDefinition = async (id?: string, key?: string) => { |
|||
return await request.get({ |
|||
url: '/bpm/process-definition/get', |
|||
params: { id, key } |
|||
}) |
|||
} |
|||
|
|||
export const getProcessDefinitionPage = async (params) => { |
|||
return await request.get({ |
|||
url: '/bpm/process-definition/page', |
|||
params |
|||
}) |
|||
} |
|||
|
|||
export const getProcessDefinitionList = async (params) => { |
|||
return await request.get({ |
|||
url: '/bpm/process-definition/list', |
|||
params |
|||
}) |
|||
} |
|||
|
|||
export const getSimpleProcessDefinitionList = async () => { |
|||
return await request.get({ |
|||
url: '/bpm/process-definition/simple-list' |
|||
}) |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export type FormVO = { |
|||
id: number |
|||
name: string |
|||
conf: string |
|||
fields: string[] |
|||
status: number |
|||
remark: string |
|||
createTime: string |
|||
} |
|||
|
|||
// 创建工作流的表单定义
|
|||
export const createForm = async (data: FormVO) => { |
|||
return await request.post({ |
|||
url: '/bpm/form/create', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
// 更新工作流的表单定义
|
|||
export const updateForm = async (data: FormVO) => { |
|||
return await request.put({ |
|||
url: '/bpm/form/update', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
// 删除工作流的表单定义
|
|||
export const deleteForm = async (id: number) => { |
|||
return await request.delete({ |
|||
url: '/bpm/form/delete?id=' + id |
|||
}) |
|||
} |
|||
|
|||
// 获得工作流的表单定义
|
|||
export const getForm = async (id: number) => { |
|||
return await request.get({ |
|||
url: '/bpm/form/get?id=' + id |
|||
}) |
|||
} |
|||
|
|||
// 获得工作流的表单定义分页
|
|||
export const getFormPage = async (params) => { |
|||
return await request.get({ |
|||
url: '/bpm/form/page', |
|||
params |
|||
}) |
|||
} |
|||
|
|||
// 获得动态表单的精简列表
|
|||
export const getFormSimpleList = async () => { |
|||
return await request.get({ |
|||
url: '/bpm/form/simple-list' |
|||
}) |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export type LeaveVO = { |
|||
id: number |
|||
status: number |
|||
type: number |
|||
reason: string |
|||
processInstanceId: string |
|||
startTime: string |
|||
endTime: string |
|||
createTime: string |
|||
} |
|||
|
|||
// 创建请假申请
|
|||
export const createLeave = async (data: LeaveVO) => { |
|||
return await request.post({ url: '/bpm/oa/leave/create', data: data }) |
|||
} |
|||
|
|||
// 获得请假申请
|
|||
export const getLeave = async (id: number) => { |
|||
return await request.get({ url: '/bpm/oa/leave/get?id=' + id }) |
|||
} |
|||
|
|||
// 获得请假申请分页
|
|||
export const getLeavePage = async (params: PageParam) => { |
|||
return await request.get({ url: '/bpm/oa/leave/page', params }) |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export type ProcessDefinitionVO = { |
|||
id: string |
|||
version: number |
|||
deploymentTIme: string |
|||
suspensionState: number |
|||
formType?: number |
|||
} |
|||
|
|||
export type ModelVO = { |
|||
id: number |
|||
formName: string |
|||
key: string |
|||
name: string |
|||
description: string |
|||
category: string |
|||
formType: number |
|||
formId: number |
|||
formCustomCreatePath: string |
|||
formCustomViewPath: string |
|||
processDefinition: ProcessDefinitionVO |
|||
status: number |
|||
remark: string |
|||
createTime: string |
|||
bpmnXml: string |
|||
} |
|||
|
|||
export const getModelList = async (name: string | undefined) => { |
|||
return await request.get({ url: '/bpm/model/list', params: { name } }) |
|||
} |
|||
|
|||
export const getModel = async (id: string) => { |
|||
return await request.get({ url: '/bpm/model/get?id=' + id }) |
|||
} |
|||
|
|||
export const updateModel = async (data: ModelVO) => { |
|||
return await request.put({ url: '/bpm/model/update', data: data }) |
|||
} |
|||
|
|||
// 批量修改流程分类的排序
|
|||
export const updateModelSortBatch = async (ids: number[]) => { |
|||
return await request.put({ |
|||
url: `/bpm/model/update-sort-batch`, |
|||
params: { |
|||
ids: ids.join(',') |
|||
} |
|||
}) |
|||
} |
|||
|
|||
export const updateModelBpmn = async (data: ModelVO) => { |
|||
return await request.put({ url: '/bpm/model/update-bpmn', data: data }) |
|||
} |
|||
|
|||
// 任务状态修改
|
|||
export const updateModelState = async (id: number, state: number) => { |
|||
const data = { |
|||
id: id, |
|||
state: state |
|||
} |
|||
return await request.put({ url: '/bpm/model/update-state', data: data }) |
|||
} |
|||
|
|||
export const createModel = async (data: ModelVO) => { |
|||
return await request.post({ url: '/bpm/model/create', data: data }) |
|||
} |
|||
|
|||
export const deleteModel = async (id: number) => { |
|||
return await request.delete({ url: '/bpm/model/delete?id=' + id }) |
|||
} |
|||
|
|||
export const deployModel = async (id: number) => { |
|||
return await request.post({ url: '/bpm/model/deploy?id=' + id }) |
|||
} |
|||
|
|||
export const cleanModel = async (id: number) => { |
|||
return await request.delete({ url: '/bpm/model/clean?id=' + id }) |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// BPM 流程表达式 VO
|
|||
export interface ProcessExpressionVO { |
|||
id: number // 编号
|
|||
name: string // 表达式名字
|
|||
status: number // 表达式状态
|
|||
expression: string // 表达式
|
|||
} |
|||
|
|||
// BPM 流程表达式 API
|
|||
export const ProcessExpressionApi = { |
|||
// 查询BPM 流程表达式分页
|
|||
getProcessExpressionPage: async (params: any) => { |
|||
return await request.get({ url: `/bpm/process-expression/page`, params }) |
|||
}, |
|||
|
|||
// 查询BPM 流程表达式详情
|
|||
getProcessExpression: async (id: number) => { |
|||
return await request.get({ url: `/bpm/process-expression/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增BPM 流程表达式
|
|||
createProcessExpression: async (data: ProcessExpressionVO) => { |
|||
return await request.post({ url: `/bpm/process-expression/create`, data }) |
|||
}, |
|||
|
|||
// 修改BPM 流程表达式
|
|||
updateProcessExpression: async (data: ProcessExpressionVO) => { |
|||
return await request.put({ url: `/bpm/process-expression/update`, data }) |
|||
}, |
|||
|
|||
// 删除BPM 流程表达式
|
|||
deleteProcessExpression: async (id: number) => { |
|||
return await request.delete({ url: `/bpm/process-expression/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 导出BPM 流程表达式 Excel
|
|||
exportProcessExpression: async (params) => { |
|||
return await request.download({ url: `/bpm/process-expression/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
import request from '@/config/axios' |
|||
import { ProcessDefinitionVO } from '@/api/bpm/model' |
|||
import { NodeType, CandidateStrategy } from '@/components/SimpleProcessDesignerV2/src/consts' |
|||
export type Task = { |
|||
id: string |
|||
name: string |
|||
} |
|||
|
|||
export type ProcessInstanceVO = { |
|||
id: number |
|||
name: string |
|||
processDefinitionId: string |
|||
category: string |
|||
result: number |
|||
tasks: Task[] |
|||
fields: string[] |
|||
status: number |
|||
remark: string |
|||
businessKey: string |
|||
createTime: string |
|||
endTime: string |
|||
processDefinition?: ProcessDefinitionVO |
|||
} |
|||
|
|||
// 用户信息
|
|||
export type User = { |
|||
id: number |
|||
nickname: string |
|||
avatar: string |
|||
} |
|||
|
|||
// 审批任务信息
|
|||
export type ApprovalTaskInfo = { |
|||
id: number |
|||
ownerUser: User |
|||
assigneeUser: User |
|||
status: number |
|||
reason: string |
|||
signPicUrl: string |
|||
} |
|||
|
|||
// 审批节点信息
|
|||
export type ApprovalNodeInfo = { |
|||
id: number |
|||
name: string |
|||
nodeType: NodeType |
|||
candidateStrategy?: CandidateStrategy |
|||
status: number |
|||
startTime?: Date |
|||
endTime?: Date |
|||
processInstanceId?: string |
|||
candidateUsers?: User[] |
|||
tasks: ApprovalTaskInfo[] |
|||
} |
|||
|
|||
export const getProcessInstanceMyPage = async (params: any) => { |
|||
return await request.get({ url: '/bpm/process-instance/my-page', params }) |
|||
} |
|||
|
|||
export const getProcessInstanceManagerPage = async (params: any) => { |
|||
return await request.get({ url: '/bpm/process-instance/manager-page', params }) |
|||
} |
|||
|
|||
export const createProcessInstance = async (data) => { |
|||
return await request.post({ url: '/bpm/process-instance/create', data: data }) |
|||
} |
|||
|
|||
export const cancelProcessInstanceByStartUser = async (id: number, reason: string) => { |
|||
const data = { |
|||
id: id, |
|||
reason: reason |
|||
} |
|||
return await request.delete({ url: '/bpm/process-instance/cancel-by-start-user', data: data }) |
|||
} |
|||
|
|||
export const cancelProcessInstanceByAdmin = async (id: number, reason: string) => { |
|||
const data = { |
|||
id: id, |
|||
reason: reason |
|||
} |
|||
return await request.delete({ url: '/bpm/process-instance/cancel-by-admin', data: data }) |
|||
} |
|||
|
|||
export const getProcessInstance = async (id: string) => { |
|||
return await request.get({ url: '/bpm/process-instance/get?id=' + id }) |
|||
} |
|||
|
|||
export const getProcessInstanceCopyPage = async (params: any) => { |
|||
return await request.get({ url: '/bpm/process-instance/copy/page', params }) |
|||
} |
|||
|
|||
// 获取审批详情
|
|||
export const getApprovalDetail = async (params: any) => { |
|||
return await request.get({ url: '/bpm/process-instance/get-approval-detail', params }) |
|||
} |
|||
|
|||
// 获取下一个执行的流程节点
|
|||
export const getNextApprovalNodes = async (params: any) => { |
|||
return await request.get({ url: '/bpm/process-instance/get-next-approval-nodes', params }) |
|||
} |
|||
|
|||
// 获取表单字段权限
|
|||
export const getFormFieldsPermission = async (params: any) => { |
|||
return await request.get({ url: '/bpm/process-instance/get-form-fields-permission', params }) |
|||
} |
|||
|
|||
// 获取流程实例的 BPMN 模型视图
|
|||
export const getProcessInstanceBpmnModelView = async (id: string) => { |
|||
return await request.get({ url: '/bpm/process-instance/get-bpmn-model-view?id=' + id }) |
|||
} |
|||
|
|||
// 获取流程实例打印数据
|
|||
export const getProcessInstancePrintData = async (id: string) => { |
|||
return await request.get({ url: '/bpm/process-instance/get-print-data?processInstanceId=' + id }) |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// BPM 流程监听器 VO
|
|||
export interface ProcessListenerVO { |
|||
id: number // 编号
|
|||
name: string // 监听器名字
|
|||
type: string // 监听器类型
|
|||
status: number // 监听器状态
|
|||
event: string // 监听事件
|
|||
valueType: string // 监听器值类型
|
|||
value: string // 监听器值
|
|||
} |
|||
|
|||
// BPM 流程监听器 API
|
|||
export const ProcessListenerApi = { |
|||
// 查询流程监听器分页
|
|||
getProcessListenerPage: async (params: any) => { |
|||
return await request.get({ url: `/bpm/process-listener/page`, params }) |
|||
}, |
|||
|
|||
// 查询流程监听器详情
|
|||
getProcessListener: async (id: number) => { |
|||
return await request.get({ url: `/bpm/process-listener/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增流程监听器
|
|||
createProcessListener: async (data: ProcessListenerVO) => { |
|||
return await request.post({ url: `/bpm/process-listener/create`, data }) |
|||
}, |
|||
|
|||
// 修改流程监听器
|
|||
updateProcessListener: async (data: ProcessListenerVO) => { |
|||
return await request.put({ url: `/bpm/process-listener/update`, data }) |
|||
}, |
|||
|
|||
// 删除流程监听器
|
|||
deleteProcessListener: async (id: number) => { |
|||
return await request.delete({ url: `/bpm/process-listener/delete?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
|
|||
export const updateBpmSimpleModel = async (data) => { |
|||
return await request.post({ |
|||
url: '/bpm/model/simple/update', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
export const getBpmSimpleModel = async (id) => { |
|||
return await request.get({ |
|||
url: '/bpm/model/simple/get?id=' + id |
|||
}) |
|||
} |
|||
@ -0,0 +1,122 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
/** |
|||
* 任务状态枚举 |
|||
*/ |
|||
export enum TaskStatusEnum { |
|||
/** |
|||
* 跳过 |
|||
*/ |
|||
SKIP = -2, |
|||
/** |
|||
* 未开始 |
|||
*/ |
|||
NOT_START = -1, |
|||
|
|||
/** |
|||
* 待审批 |
|||
*/ |
|||
WAIT = 0, |
|||
/** |
|||
* 审批中 |
|||
*/ |
|||
RUNNING = 1, |
|||
/** |
|||
* 审批通过 |
|||
*/ |
|||
APPROVE = 2, |
|||
|
|||
/** |
|||
* 审批不通过 |
|||
*/ |
|||
REJECT = 3, |
|||
|
|||
/** |
|||
* 已取消 |
|||
*/ |
|||
CANCEL = 4, |
|||
/** |
|||
* 已退回 |
|||
*/ |
|||
RETURN = 5, |
|||
/** |
|||
* 审批通过中 |
|||
*/ |
|||
APPROVING = 7 |
|||
} |
|||
|
|||
export const getTaskTodoPage = async (params: any) => { |
|||
return await request.get({ url: '/bpm/task/todo-page', params }) |
|||
} |
|||
|
|||
export const getTaskDonePage = async (params: any) => { |
|||
return await request.get({ url: '/bpm/task/done-page', params }) |
|||
} |
|||
|
|||
export const getTaskManagerPage = async (params: any) => { |
|||
return await request.get({ url: '/bpm/task/manager-page', params }) |
|||
} |
|||
|
|||
export const approveTask = async (data: any) => { |
|||
return await request.put({ url: '/bpm/task/approve', data }) |
|||
} |
|||
|
|||
export const rejectTask = async (data: any) => { |
|||
return await request.put({ url: '/bpm/task/reject', data }) |
|||
} |
|||
|
|||
export const getTaskListByProcessInstanceId = async (processInstanceId: string) => { |
|||
return await request.get({ |
|||
url: '/bpm/task/list-by-process-instance-id?processInstanceId=' + processInstanceId |
|||
}) |
|||
} |
|||
|
|||
// 获取所有可退回的节点
|
|||
export const getTaskListByReturn = async (id: string) => { |
|||
return await request.get({ url: '/bpm/task/list-by-return', params: { id } }) |
|||
} |
|||
|
|||
// 退回
|
|||
export const returnTask = async (data: any) => { |
|||
return await request.put({ url: '/bpm/task/return', data }) |
|||
} |
|||
|
|||
// 委派
|
|||
export const delegateTask = async (data: any) => { |
|||
return await request.put({ url: '/bpm/task/delegate', data }) |
|||
} |
|||
|
|||
// 转派
|
|||
export const transferTask = async (data: any) => { |
|||
return await request.put({ url: '/bpm/task/transfer', data }) |
|||
} |
|||
|
|||
// 加签
|
|||
export const signCreateTask = async (data: any) => { |
|||
return await request.put({ url: '/bpm/task/create-sign', data }) |
|||
} |
|||
|
|||
// 减签
|
|||
export const signDeleteTask = async (data: any) => { |
|||
return await request.delete({ url: '/bpm/task/delete-sign', data }) |
|||
} |
|||
|
|||
// 抄送
|
|||
export const copyTask = async (data: any) => { |
|||
return await request.put({ url: '/bpm/task/copy', data }) |
|||
} |
|||
|
|||
// 撤回
|
|||
export const withdrawTask = async (taskId: string) => { |
|||
return await request.put({ url: '/bpm/task/withdraw', params: { taskId } }) |
|||
} |
|||
|
|||
// 获取我的待办任务
|
|||
export const myTodoTask = async (processInstanceId: string) => { |
|||
return await request.get({ url: '/bpm/task/my-todo?processInstanceId=' + processInstanceId }) |
|||
} |
|||
|
|||
// 获取减签任务列表
|
|||
export const getChildrenTaskList = async (id: string) => { |
|||
return await request.get({ url: '/bpm/task/list-by-parent-task-id?parentTaskId=' + id }) |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export type UserGroupVO = { |
|||
id: number |
|||
name: string |
|||
description: string |
|||
userIds: number[] |
|||
status: number |
|||
remark: string |
|||
createTime: string |
|||
} |
|||
|
|||
// 创建用户组
|
|||
export const createUserGroup = async (data: UserGroupVO) => { |
|||
return await request.post({ |
|||
url: '/bpm/user-group/create', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
// 更新用户组
|
|||
export const updateUserGroup = async (data: UserGroupVO) => { |
|||
return await request.put({ |
|||
url: '/bpm/user-group/update', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
// 删除用户组
|
|||
export const deleteUserGroup = async (id: number) => { |
|||
return await request.delete({ url: '/bpm/user-group/delete?id=' + id }) |
|||
} |
|||
|
|||
// 获得用户组
|
|||
export const getUserGroup = async (id: number) => { |
|||
return await request.get({ url: '/bpm/user-group/get?id=' + id }) |
|||
} |
|||
|
|||
// 获得用户组分页
|
|||
export const getUserGroupPage = async (params) => { |
|||
return await request.get({ url: '/bpm/user-group/page', params }) |
|||
} |
|||
|
|||
// 获取用户组精简信息列表
|
|||
export const getUserGroupSimpleList = async (): Promise<UserGroupVO[]> => { |
|||
return await request.get({ url: '/bpm/user-group/simple-list' }) |
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
import request from '@/config/axios' |
|||
import { TransferReqVO } from '@/api/crm/permission' |
|||
|
|||
export interface BusinessVO { |
|||
id: number |
|||
name: string |
|||
customerId: number |
|||
customerName?: string |
|||
followUpStatus: boolean |
|||
contactLastTime: Date |
|||
contactNextTime: Date |
|||
ownerUserId: number |
|||
ownerUserName?: string // 负责人的用户名称
|
|||
ownerUserDept?: string // 负责人的部门名称
|
|||
statusTypeId: number |
|||
statusTypeName?: string |
|||
statusId: number |
|||
statusName?: string |
|||
endStatus: number |
|||
endRemark: string |
|||
dealTime: Date |
|||
totalProductPrice: number |
|||
totalPrice: number |
|||
discountPercent: number |
|||
remark: string |
|||
creator: string // 创建人
|
|||
creatorName?: string // 创建人名称
|
|||
createTime: Date // 创建时间
|
|||
updateTime: Date // 更新时间
|
|||
products?: [ |
|||
{ |
|||
id: number |
|||
productId: number |
|||
productName: string |
|||
productNo: string |
|||
productUnit: number |
|||
productPrice: number |
|||
businessPrice: number |
|||
count: number |
|||
totalPrice: number |
|||
} |
|||
] |
|||
} |
|||
|
|||
// 查询 CRM 商机列表
|
|||
export const getBusinessPage = async (params) => { |
|||
return await request.get({ url: `/crm/business/page`, params }) |
|||
} |
|||
|
|||
// 查询 CRM 商机列表,基于指定客户
|
|||
export const getBusinessPageByCustomer = async (params) => { |
|||
return await request.get({ url: `/crm/business/page-by-customer`, params }) |
|||
} |
|||
|
|||
// 查询 CRM 商机详情
|
|||
export const getBusiness = async (id: number) => { |
|||
return await request.get({ url: `/crm/business/get?id=` + id }) |
|||
} |
|||
|
|||
// 获得 CRM 商机列表(精简)
|
|||
export const getSimpleBusinessList = async () => { |
|||
return await request.get({ url: `/crm/business/simple-all-list` }) |
|||
} |
|||
|
|||
// 新增 CRM 商机
|
|||
export const createBusiness = async (data: BusinessVO) => { |
|||
return await request.post({ url: `/crm/business/create`, data }) |
|||
} |
|||
|
|||
// 修改 CRM 商机
|
|||
export const updateBusiness = async (data: BusinessVO) => { |
|||
return await request.put({ url: `/crm/business/update`, data }) |
|||
} |
|||
|
|||
// 修改 CRM 商机状态
|
|||
export const updateBusinessStatus = async (data: BusinessVO) => { |
|||
return await request.put({ url: `/crm/business/update-status`, data }) |
|||
} |
|||
|
|||
// 删除 CRM 商机
|
|||
export const deleteBusiness = async (id: number) => { |
|||
return await request.delete({ url: `/crm/business/delete?id=` + id }) |
|||
} |
|||
|
|||
// 导出 CRM 商机 Excel
|
|||
export const exportBusiness = async (params) => { |
|||
return await request.download({ url: `/crm/business/export-excel`, params }) |
|||
} |
|||
|
|||
// 联系人关联商机列表
|
|||
export const getBusinessPageByContact = async (params) => { |
|||
return await request.get({ url: `/crm/business/page-by-contact`, params }) |
|||
} |
|||
|
|||
// 商机转移
|
|||
export const transferBusiness = async (data: TransferReqVO) => { |
|||
return await request.put({ url: '/crm/business/transfer', data }) |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface BusinessStatusTypeVO { |
|||
id: number |
|||
name: string |
|||
deptIds: number[] |
|||
statuses?: { |
|||
id: number |
|||
name: string |
|||
percent: number |
|||
} |
|||
} |
|||
|
|||
export const DEFAULT_STATUSES = [ |
|||
{ |
|||
endStatus: 1, |
|||
key: '结束', |
|||
name: '赢单', |
|||
percent: 100 |
|||
}, |
|||
{ |
|||
endStatus: 2, |
|||
key: '结束', |
|||
name: '输单', |
|||
percent: 0 |
|||
}, |
|||
{ |
|||
endStatus: 3, |
|||
key: '结束', |
|||
name: '无效', |
|||
percent: 0 |
|||
} |
|||
] |
|||
|
|||
// 查询商机状态组列表
|
|||
export const getBusinessStatusPage = async (params: any) => { |
|||
return await request.get({ url: `/crm/business-status/page`, params }) |
|||
} |
|||
|
|||
// 新增商机状态组
|
|||
export const createBusinessStatus = async (data: BusinessStatusTypeVO) => { |
|||
return await request.post({ url: `/crm/business-status/create`, data }) |
|||
} |
|||
|
|||
// 修改商机状态组
|
|||
export const updateBusinessStatus = async (data: BusinessStatusTypeVO) => { |
|||
return await request.put({ url: `/crm/business-status/update`, data }) |
|||
} |
|||
|
|||
// 查询商机状态类型详情
|
|||
export const getBusinessStatus = async (id: number) => { |
|||
return await request.get({ url: `/crm/business-status/get?id=` + id }) |
|||
} |
|||
|
|||
// 删除商机状态
|
|||
export const deleteBusinessStatus = async (id: number) => { |
|||
return await request.delete({ url: `/crm/business-status/delete?id=` + id }) |
|||
} |
|||
|
|||
// 获得商机状态组列表
|
|||
export const getBusinessStatusTypeSimpleList = async () => { |
|||
return await request.get({ url: `/crm/business-status/type-simple-list` }) |
|||
} |
|||
|
|||
// 获得商机阶段列表
|
|||
export const getBusinessStatusSimpleList = async (typeId: number) => { |
|||
return await request.get({ url: `/crm/business-status/status-simple-list`, params: { typeId } }) |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
import request from '@/config/axios' |
|||
import { TransferReqVO } from '@/api/crm/permission' |
|||
|
|||
export interface ClueVO { |
|||
id: number // 编号
|
|||
name: string // 线索名称
|
|||
followUpStatus: boolean // 跟进状态
|
|||
contactLastTime: Date // 最后跟进时间
|
|||
contactLastContent: string // 最后跟进内容
|
|||
contactNextTime: Date // 下次联系时间
|
|||
ownerUserId: number // 负责人的用户编号
|
|||
ownerUserName?: string // 负责人的用户名称
|
|||
ownerUserDept?: string // 负责人的部门名称
|
|||
transformStatus: boolean // 转化状态
|
|||
customerId: number // 客户编号
|
|||
customerName?: string // 客户名称
|
|||
mobile: string // 手机号
|
|||
telephone: string // 电话
|
|||
qq: string // QQ
|
|||
wechat: string // wechat
|
|||
email: string // email
|
|||
areaId: number // 所在地
|
|||
areaName?: string // 所在地名称
|
|||
detailAddress: string // 详细地址
|
|||
industryId: number // 所属行业
|
|||
level: number // 客户等级
|
|||
source: number // 客户来源
|
|||
remark: string // 备注
|
|||
creator: string // 创建人
|
|||
creatorName?: string // 创建人名称
|
|||
createTime: Date // 创建时间
|
|||
updateTime: Date // 更新时间
|
|||
} |
|||
|
|||
// 查询线索列表
|
|||
export const getCluePage = async (params: any) => { |
|||
return await request.get({ url: `/crm/clue/page`, params }) |
|||
} |
|||
|
|||
// 查询线索详情
|
|||
export const getClue = async (id: number) => { |
|||
return await request.get({ url: `/crm/clue/get?id=` + id }) |
|||
} |
|||
|
|||
// 新增线索
|
|||
export const createClue = async (data: ClueVO) => { |
|||
return await request.post({ url: `/crm/clue/create`, data }) |
|||
} |
|||
|
|||
// 修改线索
|
|||
export const updateClue = async (data: ClueVO) => { |
|||
return await request.put({ url: `/crm/clue/update`, data }) |
|||
} |
|||
|
|||
// 删除线索
|
|||
export const deleteClue = async (id: number) => { |
|||
return await request.delete({ url: `/crm/clue/delete?id=` + id }) |
|||
} |
|||
|
|||
// 导出线索 Excel
|
|||
export const exportClue = async (params) => { |
|||
return await request.download({ url: `/crm/clue/export-excel`, params }) |
|||
} |
|||
|
|||
// 线索转移
|
|||
export const transferClue = async (data: TransferReqVO) => { |
|||
return await request.put({ url: '/crm/clue/transfer', data }) |
|||
} |
|||
|
|||
// 线索转化为客户
|
|||
export const transformClue = async (id: number) => { |
|||
return await request.put({ url: '/crm/clue/transform', params: { id } }) |
|||
} |
|||
|
|||
// 获得分配给我的、待跟进的线索数量
|
|||
export const getFollowClueCount = async () => { |
|||
return await request.get({ url: '/crm/clue/follow-count' }) |
|||
} |
|||
@ -0,0 +1,113 @@ |
|||
import request from '@/config/axios' |
|||
import { TransferReqVO } from '@/api/crm/permission' |
|||
|
|||
export interface ContactVO { |
|||
id: number // 编号
|
|||
name: string // 联系人名称
|
|||
customerId: number // 客户编号
|
|||
customerName?: string // 客户名称
|
|||
contactLastTime: Date // 最后跟进时间
|
|||
contactLastContent: string // 最后跟进内容
|
|||
contactNextTime: Date // 下次联系时间
|
|||
ownerUserId: number // 负责人的用户编号
|
|||
ownerUserName?: string // 负责人的用户名称
|
|||
ownerUserDept?: string // 负责人的部门名称
|
|||
mobile: string // 手机号
|
|||
telephone: string // 电话
|
|||
qq: string // QQ
|
|||
wechat: string // wechat
|
|||
email: string // email
|
|||
areaId: number // 所在地
|
|||
areaName?: string // 所在地名称
|
|||
detailAddress: string // 详细地址
|
|||
sex: number // 性别
|
|||
master: boolean // 是否主联系人
|
|||
post: string // 职务
|
|||
parentId: number // 上级联系人编号
|
|||
parentName?: string // 上级联系人名称
|
|||
remark: string // 备注
|
|||
creator: string // 创建人
|
|||
creatorName?: string // 创建人名称
|
|||
createTime: Date // 创建时间
|
|||
updateTime: Date // 更新时间
|
|||
} |
|||
|
|||
export interface ContactBusinessReqVO { |
|||
contactId: number |
|||
businessIds: number[] |
|||
} |
|||
|
|||
export interface ContactBusiness2ReqVO { |
|||
businessId: number |
|||
contactIds: number[] |
|||
} |
|||
|
|||
// 查询 CRM 联系人列表
|
|||
export const getContactPage = async (params) => { |
|||
return await request.get({ url: `/crm/contact/page`, params }) |
|||
} |
|||
|
|||
// 查询 CRM 联系人列表,基于指定客户
|
|||
export const getContactPageByCustomer = async (params: any) => { |
|||
return await request.get({ url: `/crm/contact/page-by-customer`, params }) |
|||
} |
|||
|
|||
// 查询 CRM 联系人列表,基于指定商机
|
|||
export const getContactPageByBusiness = async (params: any) => { |
|||
return await request.get({ url: `/crm/contact/page-by-business`, params }) |
|||
} |
|||
|
|||
// 查询 CRM 联系人详情
|
|||
export const getContact = async (id: number) => { |
|||
return await request.get({ url: `/crm/contact/get?id=` + id }) |
|||
} |
|||
|
|||
// 新增 CRM 联系人
|
|||
export const createContact = async (data: ContactVO) => { |
|||
return await request.post({ url: `/crm/contact/create`, data }) |
|||
} |
|||
|
|||
// 修改 CRM 联系人
|
|||
export const updateContact = async (data: ContactVO) => { |
|||
return await request.put({ url: `/crm/contact/update`, data }) |
|||
} |
|||
|
|||
// 删除 CRM 联系人
|
|||
export const deleteContact = async (id: number) => { |
|||
return await request.delete({ url: `/crm/contact/delete?id=` + id }) |
|||
} |
|||
|
|||
// 导出 CRM 联系人 Excel
|
|||
export const exportContact = async (params) => { |
|||
return await request.download({ url: `/crm/contact/export-excel`, params }) |
|||
} |
|||
|
|||
// 获得 CRM 联系人列表(精简)
|
|||
export const getSimpleContactList = async () => { |
|||
return await request.get({ url: `/crm/contact/simple-all-list` }) |
|||
} |
|||
|
|||
// 批量新增联系人商机关联
|
|||
export const createContactBusinessList = async (data: ContactBusinessReqVO) => { |
|||
return await request.post({ url: `/crm/contact/create-business-list`, data }) |
|||
} |
|||
|
|||
// 批量新增联系人商机关联
|
|||
export const createContactBusinessList2 = async (data: ContactBusiness2ReqVO) => { |
|||
return await request.post({ url: `/crm/contact/create-business-list2`, data }) |
|||
} |
|||
|
|||
// 解除联系人商机关联
|
|||
export const deleteContactBusinessList = async (data: ContactBusinessReqVO) => { |
|||
return await request.delete({ url: `/crm/contact/delete-business-list`, data }) |
|||
} |
|||
|
|||
// 解除联系人商机关联
|
|||
export const deleteContactBusinessList2 = async (data: ContactBusiness2ReqVO) => { |
|||
return await request.delete({ url: `/crm/contact/delete-business-list2`, data }) |
|||
} |
|||
|
|||
// 联系人转移
|
|||
export const transferContact = async (data: TransferReqVO) => { |
|||
return await request.put({ url: '/crm/contact/transfer', data }) |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface ContractConfigVO { |
|||
notifyEnabled?: boolean |
|||
notifyDays?: number |
|||
} |
|||
|
|||
// 获取合同配置
|
|||
export const getContractConfig = async () => { |
|||
return await request.get({ url: `/crm/contract-config/get` }) |
|||
} |
|||
|
|||
// 更新合同配置
|
|||
export const saveContractConfig = async (data: ContractConfigVO) => { |
|||
return await request.put({ url: `/crm/contract-config/save`, data }) |
|||
} |
|||
@ -0,0 +1,114 @@ |
|||
import request from '@/config/axios' |
|||
import { TransferReqVO } from '@/api/crm/permission' |
|||
|
|||
export interface ContractVO { |
|||
id: number |
|||
name: string |
|||
no: string |
|||
customerId: number |
|||
customerName?: string |
|||
businessId: number |
|||
businessName: string |
|||
contactLastTime: Date |
|||
ownerUserId: number |
|||
ownerUserName?: string |
|||
ownerUserDeptName?: string |
|||
processInstanceId: number |
|||
auditStatus: number |
|||
orderDate: Date |
|||
startTime: Date |
|||
endTime: Date |
|||
totalProductPrice: number |
|||
discountPercent: number |
|||
totalPrice: number |
|||
totalReceivablePrice: number |
|||
signContactId: number |
|||
signContactName?: string |
|||
signUserId: number |
|||
signUserName: string |
|||
remark: string |
|||
createTime?: Date |
|||
creator: string |
|||
creatorName: string |
|||
updateTime?: Date |
|||
products?: [ |
|||
{ |
|||
id: number |
|||
productId: number |
|||
productName: string |
|||
productNo: string |
|||
productUnit: number |
|||
productPrice: number |
|||
contractPrice: number |
|||
count: number |
|||
totalPrice: number |
|||
} |
|||
] |
|||
} |
|||
|
|||
// 查询 CRM 合同列表
|
|||
export const getContractPage = async (params) => { |
|||
return await request.get({ url: `/crm/contract/page`, params }) |
|||
} |
|||
|
|||
// 查询 CRM 联系人列表,基于指定客户
|
|||
export const getContractPageByCustomer = async (params: any) => { |
|||
return await request.get({ url: `/crm/contract/page-by-customer`, params }) |
|||
} |
|||
|
|||
// 查询 CRM 联系人列表,基于指定商机
|
|||
export const getContractPageByBusiness = async (params: any) => { |
|||
return await request.get({ url: `/crm/contract/page-by-business`, params }) |
|||
} |
|||
|
|||
// 查询 CRM 合同详情
|
|||
export const getContract = async (id: number) => { |
|||
return await request.get({ url: `/crm/contract/get?id=` + id }) |
|||
} |
|||
|
|||
// 查询 CRM 合同下拉列表
|
|||
export const getContractSimpleList = async (customerId: number) => { |
|||
return await request.get({ |
|||
url: `/crm/contract/simple-list?customerId=${customerId}` |
|||
}) |
|||
} |
|||
|
|||
// 新增 CRM 合同
|
|||
export const createContract = async (data: ContractVO) => { |
|||
return await request.post({ url: `/crm/contract/create`, data }) |
|||
} |
|||
|
|||
// 修改 CRM 合同
|
|||
export const updateContract = async (data: ContractVO) => { |
|||
return await request.put({ url: `/crm/contract/update`, data }) |
|||
} |
|||
|
|||
// 删除 CRM 合同
|
|||
export const deleteContract = async (id: number) => { |
|||
return await request.delete({ url: `/crm/contract/delete?id=` + id }) |
|||
} |
|||
|
|||
// 导出 CRM 合同 Excel
|
|||
export const exportContract = async (params) => { |
|||
return await request.download({ url: `/crm/contract/export-excel`, params }) |
|||
} |
|||
|
|||
// 提交审核
|
|||
export const submitContract = async (id: number) => { |
|||
return await request.put({ url: `/crm/contract/submit?id=${id}` }) |
|||
} |
|||
|
|||
// 合同转移
|
|||
export const transferContract = async (data: TransferReqVO) => { |
|||
return await request.put({ url: '/crm/contract/transfer', data }) |
|||
} |
|||
|
|||
// 获得待审核合同数量
|
|||
export const getAuditContractCount = async () => { |
|||
return await request.get({ url: '/crm/contract/audit-count' }) |
|||
} |
|||
|
|||
// 获得即将到期(提醒)的合同数量
|
|||
export const getRemindContractCount = async () => { |
|||
return await request.get({ url: '/crm/contract/remind-count' }) |
|||
} |
|||
@ -0,0 +1,132 @@ |
|||
import request from '@/config/axios' |
|||
import { TransferReqVO } from '@/api/crm/permission' |
|||
|
|||
export interface CustomerVO { |
|||
id: number // 编号
|
|||
name: string // 客户名称
|
|||
followUpStatus: boolean // 跟进状态
|
|||
contactLastTime: Date // 最后跟进时间
|
|||
contactLastContent: string // 最后跟进内容
|
|||
contactNextTime: Date // 下次联系时间
|
|||
ownerUserId: number // 负责人的用户编号
|
|||
ownerUserName?: string // 负责人的用户名称
|
|||
ownerUserDept?: string // 负责人的部门名称
|
|||
lockStatus?: boolean |
|||
dealStatus?: boolean |
|||
mobile: string // 手机号
|
|||
telephone: string // 电话
|
|||
qq: string // QQ
|
|||
wechat: string // wechat
|
|||
email: string // email
|
|||
areaId: number // 所在地
|
|||
areaName?: string // 所在地名称
|
|||
detailAddress: string // 详细地址
|
|||
industryId: number // 所属行业
|
|||
level: number // 客户等级
|
|||
source: number // 客户来源
|
|||
remark: string // 备注
|
|||
creator: string // 创建人
|
|||
creatorName?: string // 创建人名称
|
|||
createTime: Date // 创建时间
|
|||
updateTime: Date // 更新时间
|
|||
} |
|||
|
|||
// 查询客户列表
|
|||
export const getCustomerPage = async (params) => { |
|||
return await request.get({ url: `/crm/customer/page`, params }) |
|||
} |
|||
|
|||
// 进入公海客户提醒的客户列表
|
|||
export const getPutPoolRemindCustomerPage = async (params) => { |
|||
return await request.get({ url: `/crm/customer/put-pool-remind-page`, params }) |
|||
} |
|||
|
|||
// 获得待进入公海客户数量
|
|||
export const getPutPoolRemindCustomerCount = async () => { |
|||
return await request.get({ url: `/crm/customer/put-pool-remind-count` }) |
|||
} |
|||
|
|||
// 获得今日需联系客户数量
|
|||
export const getTodayContactCustomerCount = async () => { |
|||
return await request.get({ url: `/crm/customer/today-contact-count` }) |
|||
} |
|||
|
|||
// 获得分配给我、待跟进的线索数量的客户数量
|
|||
export const getFollowCustomerCount = async () => { |
|||
return await request.get({ url: `/crm/customer/follow-count` }) |
|||
} |
|||
|
|||
// 查询客户详情
|
|||
export const getCustomer = async (id: number) => { |
|||
return await request.get({ url: `/crm/customer/get?id=` + id }) |
|||
} |
|||
|
|||
// 新增客户
|
|||
export const createCustomer = async (data: CustomerVO) => { |
|||
return await request.post({ url: `/crm/customer/create`, data }) |
|||
} |
|||
|
|||
// 修改客户
|
|||
export const updateCustomer = async (data: CustomerVO) => { |
|||
return await request.put({ url: `/crm/customer/update`, data }) |
|||
} |
|||
|
|||
// 更新客户的成交状态
|
|||
export const updateCustomerDealStatus = async (id: number, dealStatus: boolean) => { |
|||
return await request.put({ url: `/crm/customer/update-deal-status`, params: { id, dealStatus } }) |
|||
} |
|||
|
|||
// 删除客户
|
|||
export const deleteCustomer = async (id: number) => { |
|||
return await request.delete({ url: `/crm/customer/delete?id=` + id }) |
|||
} |
|||
|
|||
// 导出客户 Excel
|
|||
export const exportCustomer = async (params: any) => { |
|||
return await request.download({ url: `/crm/customer/export-excel`, params }) |
|||
} |
|||
|
|||
// 下载客户导入模板
|
|||
export const importCustomerTemplate = () => { |
|||
return request.download({ url: '/crm/customer/get-import-template' }) |
|||
} |
|||
|
|||
// 导入客户
|
|||
export const handleImport = async (formData) => { |
|||
return await request.upload({ url: `/crm/customer/import`, data: formData }) |
|||
} |
|||
|
|||
// 客户列表
|
|||
export const getCustomerSimpleList = async () => { |
|||
return await request.get({ url: `/crm/customer/simple-list` }) |
|||
} |
|||
|
|||
// ======================= 业务操作 =======================
|
|||
|
|||
// 客户转移
|
|||
export const transferCustomer = async (data: TransferReqVO) => { |
|||
return await request.put({ url: '/crm/customer/transfer', data }) |
|||
} |
|||
|
|||
// 锁定/解锁客户
|
|||
export const lockCustomer = async (id: number, lockStatus: boolean) => { |
|||
return await request.put({ url: `/crm/customer/lock`, data: { id, lockStatus } }) |
|||
} |
|||
|
|||
// 领取公海客户
|
|||
export const receiveCustomer = async (ids: any[]) => { |
|||
return await request.put({ url: '/crm/customer/receive', params: { ids: ids.join(',') } }) |
|||
} |
|||
|
|||
// 分配公海给对应负责人
|
|||
export const distributeCustomer = async (ids: any[], ownerUserId: number) => { |
|||
return await request.put({ |
|||
url: '/crm/customer/distribute', |
|||
data: { ids: ids, ownerUserId } |
|||
}) |
|||
} |
|||
|
|||
// 客户放入公海
|
|||
export const putCustomerPool = async (id: number) => { |
|||
return await request.put({ url: `/crm/customer/put-pool?id=${id}` }) |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface CustomerLimitConfigVO { |
|||
id?: number |
|||
type?: number |
|||
userIds?: string |
|||
deptIds?: string |
|||
maxCount?: number |
|||
dealCountEnabled?: boolean |
|||
} |
|||
|
|||
/** |
|||
* 客户限制配置类型 |
|||
*/ |
|||
export enum LimitConfType { |
|||
/** |
|||
* 拥有客户数限制 |
|||
*/ |
|||
CUSTOMER_QUANTITY_LIMIT = 1, |
|||
/** |
|||
* 锁定客户数限制 |
|||
*/ |
|||
CUSTOMER_LOCK_LIMIT = 2 |
|||
} |
|||
|
|||
// 查询客户限制配置列表
|
|||
export const getCustomerLimitConfigPage = async (params) => { |
|||
return await request.get({ url: `/crm/customer-limit-config/page`, params }) |
|||
} |
|||
|
|||
// 查询客户限制配置详情
|
|||
export const getCustomerLimitConfig = async (id: number) => { |
|||
return await request.get({ url: `/crm/customer-limit-config/get?id=` + id }) |
|||
} |
|||
|
|||
// 新增客户限制配置
|
|||
export const createCustomerLimitConfig = async (data: CustomerLimitConfigVO) => { |
|||
return await request.post({ url: `/crm/customer-limit-config/create`, data }) |
|||
} |
|||
|
|||
// 修改客户限制配置
|
|||
export const updateCustomerLimitConfig = async (data: CustomerLimitConfigVO) => { |
|||
return await request.put({ url: `/crm/customer-limit-config/update`, data }) |
|||
} |
|||
|
|||
// 删除客户限制配置
|
|||
export const deleteCustomerLimitConfig = async (id: number) => { |
|||
return await request.delete({ url: `/crm/customer-limit-config/delete?id=` + id }) |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface CustomerPoolConfigVO { |
|||
enabled?: boolean |
|||
contactExpireDays?: number |
|||
dealExpireDays?: number |
|||
notifyEnabled?: boolean |
|||
notifyDays?: number |
|||
} |
|||
|
|||
// 获取客户公海规则设置
|
|||
export const getCustomerPoolConfig = async () => { |
|||
return await request.get({ url: `/crm/customer-pool-config/get` }) |
|||
} |
|||
|
|||
// 更新客户公海规则设置
|
|||
export const saveCustomerPoolConfig = async (data: CustomerPoolConfigVO) => { |
|||
return await request.put({ url: `/crm/customer-pool-config/save`, data }) |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// 跟进记录 VO
|
|||
export interface FollowUpRecordVO { |
|||
id: number // 编号
|
|||
bizType: number // 数据类型
|
|||
bizId: number // 数据编号
|
|||
type: number // 跟进类型
|
|||
content: string // 跟进内容
|
|||
picUrls: string[] // 图片
|
|||
fileUrls: string[] // 附件
|
|||
nextTime: Date // 下次联系时间
|
|||
businessIds: number[] // 关联的商机编号数组
|
|||
businesses: { |
|||
id: number |
|||
name: string |
|||
}[] // 关联的商机数组
|
|||
contactIds: number[] // 关联的联系人编号数组
|
|||
contacts: { |
|||
id: number |
|||
name: string |
|||
}[] // 关联的联系人数组
|
|||
creator: string |
|||
creatorName?: string |
|||
} |
|||
|
|||
// 跟进记录 API
|
|||
export const FollowUpRecordApi = { |
|||
// 查询跟进记录分页
|
|||
getFollowUpRecordPage: async (params: any) => { |
|||
return await request.get({ url: `/crm/follow-up-record/page`, params }) |
|||
}, |
|||
|
|||
// 新增跟进记录
|
|||
createFollowUpRecord: async (data: FollowUpRecordVO) => { |
|||
return await request.post({ url: `/crm/follow-up-record/create`, data }) |
|||
}, |
|||
|
|||
// 删除跟进记录
|
|||
deleteFollowUpRecord: async (id: number) => { |
|||
return await request.delete({ url: `/crm/follow-up-record/delete?id=` + id }) |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface OperateLogVO extends PageParam { |
|||
bizType: number |
|||
bizId: number |
|||
} |
|||
|
|||
// 获得操作日志
|
|||
export const getOperateLogPage = async (params: OperateLogVO) => { |
|||
return await request.get({ url: `/crm/operate-log/page`, params }) |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface PermissionVO { |
|||
id?: number // 数据权限编号
|
|||
userId: number // 用户编号
|
|||
bizType: number // Crm 类型
|
|||
bizId: number // Crm 类型数据编号
|
|||
level: number // 权限级别
|
|||
toBizTypes?: number[] // 同时添加至
|
|||
deptName?: string // 部门名称
|
|||
nickname?: string // 用户昵称
|
|||
postNames?: string[] // 岗位名称数组
|
|||
createTime?: Date |
|||
ids?: number[] |
|||
} |
|||
|
|||
export interface TransferReqVO { |
|||
id: number // 模块编号
|
|||
newOwnerUserId: number // 新负责人的用户编号
|
|||
oldOwnerPermissionLevel?: number // 老负责人加入团队后的权限级别
|
|||
toBizTypes?: number[] // 转移客户时,需要额外有【联系人】【商机】【合同】的 checkbox 选择
|
|||
} |
|||
|
|||
/** |
|||
* CRM 业务类型枚举 |
|||
* |
|||
* @author HUIHUI |
|||
*/ |
|||
export enum BizTypeEnum { |
|||
CRM_CLUE = 1, // 线索
|
|||
CRM_CUSTOMER = 2, // 客户
|
|||
CRM_CONTACT = 3, // 联系人
|
|||
CRM_BUSINESS = 4, // 商机
|
|||
CRM_CONTRACT = 5, // 合同
|
|||
CRM_PRODUCT = 6, // 产品
|
|||
CRM_RECEIVABLE = 7, // 回款
|
|||
CRM_RECEIVABLE_PLAN = 8 // 回款计划
|
|||
} |
|||
|
|||
/** |
|||
* CRM 数据权限级别枚举 |
|||
*/ |
|||
export enum PermissionLevelEnum { |
|||
OWNER = 1, // 负责人
|
|||
READ = 2, // 只读
|
|||
WRITE = 3 // 读写
|
|||
} |
|||
|
|||
// 获得数据权限列表(查询团队成员列表)
|
|||
export const getPermissionList = async (params) => { |
|||
return await request.get({ url: `/crm/permission/list`, params }) |
|||
} |
|||
|
|||
// 创建数据权限(新增团队成员)
|
|||
export const createPermission = async (data: PermissionVO) => { |
|||
return await request.post({ url: `/crm/permission/create`, data }) |
|||
} |
|||
|
|||
// 编辑数据权限(修改团队成员权限级别)
|
|||
export const updatePermission = async (data) => { |
|||
return await request.put({ url: `/crm/permission/update`, data }) |
|||
} |
|||
|
|||
// 删除数据权限(删除团队成员)
|
|||
export const deletePermissionBatch = async (val: number[]) => { |
|||
return await request.delete({ url: '/crm/permission/delete?ids=' + val.join(',') }) |
|||
} |
|||
|
|||
// 删除自己的数据权限(退出团队)
|
|||
export const deleteSelfPermission = async (id: number) => { |
|||
return await request.delete({ url: '/crm/permission/delete-self?id=' + id }) |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// TODO @zange:挪到 product 下,建个 category 包,挪进去哈;
|
|||
export interface ProductCategoryVO { |
|||
id: number |
|||
name: string |
|||
parentId: number |
|||
} |
|||
|
|||
// 查询产品分类详情
|
|||
export const getProductCategory = async (id: number) => { |
|||
return await request.get({ url: `/crm/product-category/get?id=` + id }) |
|||
} |
|||
|
|||
// 新增产品分类
|
|||
export const createProductCategory = async (data: ProductCategoryVO) => { |
|||
return await request.post({ url: `/crm/product-category/create`, data }) |
|||
} |
|||
|
|||
// 修改产品分类
|
|||
export const updateProductCategory = async (data: ProductCategoryVO) => { |
|||
return await request.put({ url: `/crm/product-category/update`, data }) |
|||
} |
|||
|
|||
// 删除产品分类
|
|||
export const deleteProductCategory = async (id: number) => { |
|||
return await request.delete({ url: `/crm/product-category/delete?id=` + id }) |
|||
} |
|||
|
|||
// 产品分类列表
|
|||
export const getProductCategoryList = async (params) => { |
|||
return await request.get({ url: `/crm/product-category/list`, params }) |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface ProductVO { |
|||
id: number |
|||
name: string |
|||
no: string |
|||
unit: number |
|||
price: number |
|||
status: number |
|||
categoryId: number |
|||
categoryName?: string |
|||
description: string |
|||
ownerUserId: number |
|||
} |
|||
|
|||
// 查询产品列表
|
|||
export const getProductPage = async (params) => { |
|||
return await request.get({ url: `/crm/product/page`, params }) |
|||
} |
|||
|
|||
// 获得产品精简列表
|
|||
export const getProductSimpleList = async () => { |
|||
return await request.get({ url: `/crm/product/simple-list` }) |
|||
} |
|||
|
|||
// 查询产品详情
|
|||
export const getProduct = async (id: number) => { |
|||
return await request.get({ url: `/crm/product/get?id=` + id }) |
|||
} |
|||
|
|||
// 新增产品
|
|||
export const createProduct = async (data: ProductVO) => { |
|||
return await request.post({ url: `/crm/product/create`, data }) |
|||
} |
|||
|
|||
// 修改产品
|
|||
export const updateProduct = async (data: ProductVO) => { |
|||
return await request.put({ url: `/crm/product/update`, data }) |
|||
} |
|||
|
|||
// 删除产品
|
|||
export const deleteProduct = async (id: number) => { |
|||
return await request.delete({ url: `/crm/product/delete?id=` + id }) |
|||
} |
|||
|
|||
// 导出产品 Excel
|
|||
export const exportProduct = async (params) => { |
|||
return await request.download({ url: `/crm/product/export-excel`, params }) |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface ReceivableVO { |
|||
id: number |
|||
no: string |
|||
planId?: number |
|||
customerId?: number |
|||
customerName?: string |
|||
contractId?: number |
|||
contract?: { |
|||
id?: number |
|||
name?: string |
|||
no: string |
|||
totalPrice: number |
|||
} |
|||
auditStatus: number |
|||
processInstanceId: number |
|||
returnTime: Date |
|||
returnType: number |
|||
price: number |
|||
ownerUserId: number |
|||
ownerUserName?: string |
|||
remark: string |
|||
creator: string // 创建人
|
|||
creatorName?: string // 创建人名称
|
|||
createTime: Date // 创建时间
|
|||
updateTime: Date // 更新时间
|
|||
} |
|||
|
|||
// 查询回款列表
|
|||
export const getReceivablePage = async (params) => { |
|||
return await request.get({ url: `/crm/receivable/page`, params }) |
|||
} |
|||
|
|||
// 查询回款列表
|
|||
export const getReceivablePageByCustomer = async (params) => { |
|||
return await request.get({ url: `/crm/receivable/page-by-customer`, params }) |
|||
} |
|||
|
|||
// 查询回款详情
|
|||
export const getReceivable = async (id: number) => { |
|||
return await request.get({ url: `/crm/receivable/get?id=` + id }) |
|||
} |
|||
|
|||
// 新增回款
|
|||
export const createReceivable = async (data: ReceivableVO) => { |
|||
return await request.post({ url: `/crm/receivable/create`, data }) |
|||
} |
|||
|
|||
// 修改回款
|
|||
export const updateReceivable = async (data: ReceivableVO) => { |
|||
return await request.put({ url: `/crm/receivable/update`, data }) |
|||
} |
|||
|
|||
// 删除回款
|
|||
export const deleteReceivable = async (id: number) => { |
|||
return await request.delete({ url: `/crm/receivable/delete?id=` + id }) |
|||
} |
|||
|
|||
// 导出回款 Excel
|
|||
export const exportReceivable = async (params) => { |
|||
return await request.download({ url: `/crm/receivable/export-excel`, params }) |
|||
} |
|||
|
|||
// 提交审核
|
|||
export const submitReceivable = async (id: number) => { |
|||
return await request.put({ url: `/crm/receivable/submit?id=${id}` }) |
|||
} |
|||
|
|||
// 获得待审核回款数量
|
|||
export const getAuditReceivableCount = async () => { |
|||
return await request.get({ url: '/crm/receivable/audit-count' }) |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface ReceivablePlanVO { |
|||
id: number |
|||
period: number |
|||
receivableId: number |
|||
price: number |
|||
returnTime: Date |
|||
remindDays: number |
|||
returnType: number |
|||
remindTime: Date |
|||
customerId: number |
|||
customerName?: string |
|||
contractId?: number |
|||
contractNo?: string |
|||
ownerUserId: number |
|||
ownerUserName?: string |
|||
remark: string |
|||
creator: string // 创建人
|
|||
creatorName?: string // 创建人名称
|
|||
createTime: Date // 创建时间
|
|||
updateTime: Date // 更新时间
|
|||
receivable?: { |
|||
price: number |
|||
returnTime: Date |
|||
} |
|||
} |
|||
|
|||
// 查询回款计划列表
|
|||
export const getReceivablePlanPage = async (params) => { |
|||
return await request.get({ url: `/crm/receivable-plan/page`, params }) |
|||
} |
|||
|
|||
// 查询回款计划列表
|
|||
export const getReceivablePlanPageByCustomer = async (params) => { |
|||
return await request.get({ url: `/crm/receivable-plan/page-by-customer`, params }) |
|||
} |
|||
|
|||
// 查询回款计划详情
|
|||
export const getReceivablePlan = async (id: number) => { |
|||
return await request.get({ url: `/crm/receivable-plan/get?id=` + id }) |
|||
} |
|||
|
|||
// 查询回款计划下拉数据
|
|||
export const getReceivablePlanSimpleList = async (customerId: number, contractId: number) => { |
|||
return await request.get({ |
|||
url: `/crm/receivable-plan/simple-list?customerId=${customerId}&contractId=${contractId}` |
|||
}) |
|||
} |
|||
|
|||
// 新增回款计划
|
|||
export const createReceivablePlan = async (data: ReceivablePlanVO) => { |
|||
return await request.post({ url: `/crm/receivable-plan/create`, data }) |
|||
} |
|||
|
|||
// 修改回款计划
|
|||
export const updateReceivablePlan = async (data: ReceivablePlanVO) => { |
|||
return await request.put({ url: `/crm/receivable-plan/update`, data }) |
|||
} |
|||
|
|||
// 删除回款计划
|
|||
export const deleteReceivablePlan = async (id: number) => { |
|||
return await request.delete({ url: `/crm/receivable-plan/delete?id=` + id }) |
|||
} |
|||
|
|||
// 导出回款计划 Excel
|
|||
export const exportReceivablePlan = async (params) => { |
|||
return await request.download({ url: `/crm/receivable-plan/export-excel`, params }) |
|||
} |
|||
|
|||
// 获得待回款提醒数量
|
|||
export const getReceivablePlanRemindCount = async () => { |
|||
return await request.get({ url: '/crm/receivable-plan/remind-count' }) |
|||
} |
|||
@ -0,0 +1,168 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface CrmStatisticsCustomerSummaryByDateRespVO { |
|||
time: string |
|||
customerCreateCount: number |
|||
customerDealCount: number |
|||
} |
|||
|
|||
export interface CrmStatisticsCustomerSummaryByUserRespVO { |
|||
ownerUserName: string |
|||
customerCreateCount: number |
|||
customerDealCount: number |
|||
contractPrice: number |
|||
receivablePrice: number |
|||
} |
|||
|
|||
export interface CrmStatisticsFollowUpSummaryByDateRespVO { |
|||
time: string |
|||
followUpRecordCount: number |
|||
followUpCustomerCount: number |
|||
} |
|||
|
|||
export interface CrmStatisticsFollowUpSummaryByUserRespVO { |
|||
ownerUserName: string |
|||
followupRecordCount: number |
|||
followupCustomerCount: number |
|||
} |
|||
|
|||
export interface CrmStatisticsFollowUpSummaryByTypeRespVO { |
|||
followUpType: string |
|||
followUpRecordCount: number |
|||
} |
|||
|
|||
export interface CrmStatisticsCustomerContractSummaryRespVO { |
|||
customerName: string |
|||
contractName: string |
|||
totalPrice: number |
|||
receivablePrice: number |
|||
customerType: string |
|||
customerSource: string |
|||
ownerUserName: string |
|||
creatorUserName: string |
|||
createTime: Date |
|||
orderDate: Date |
|||
} |
|||
|
|||
export interface CrmStatisticsPoolSummaryByDateRespVO { |
|||
time: string |
|||
customerPutCount: number |
|||
customerTakeCount: number |
|||
} |
|||
|
|||
export interface CrmStatisticsPoolSummaryByUserRespVO { |
|||
ownerUserName: string |
|||
customerPutCount: number |
|||
customerTakeCount: number |
|||
} |
|||
|
|||
export interface CrmStatisticsCustomerDealCycleByDateRespVO { |
|||
time: string |
|||
customerDealCycle: number |
|||
} |
|||
|
|||
export interface CrmStatisticsCustomerDealCycleByUserRespVO { |
|||
ownerUserName: string |
|||
customerDealCycle: number |
|||
customerDealCount: number |
|||
} |
|||
|
|||
export interface CrmStatisticsCustomerDealCycleByAreaRespVO { |
|||
areaName: string |
|||
customerDealCycle: number |
|||
customerDealCount: number |
|||
} |
|||
|
|||
export interface CrmStatisticsCustomerDealCycleByProductRespVO { |
|||
productName: string |
|||
customerDealCycle: number |
|||
customerDealCount: number |
|||
} |
|||
|
|||
// 客户分析 API
|
|||
export const StatisticsCustomerApi = { |
|||
// 1.1 客户总量分析(按日期)
|
|||
getCustomerSummaryByDate: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-customer-summary-by-date', |
|||
params |
|||
}) |
|||
}, |
|||
// 1.2 客户总量分析(按用户)
|
|||
getCustomerSummaryByUser: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-customer-summary-by-user', |
|||
params |
|||
}) |
|||
}, |
|||
// 2.1 客户跟进次数分析(按日期)
|
|||
getFollowUpSummaryByDate: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-follow-up-summary-by-date', |
|||
params |
|||
}) |
|||
}, |
|||
// 2.2 客户跟进次数分析(按用户)
|
|||
getFollowUpSummaryByUser: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-follow-up-summary-by-user', |
|||
params |
|||
}) |
|||
}, |
|||
// 3.1 获取客户跟进方式统计数
|
|||
getFollowUpSummaryByType: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-follow-up-summary-by-type', |
|||
params |
|||
}) |
|||
}, |
|||
// 4.1 合同摘要信息(客户转化率页面)
|
|||
getContractSummary: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-contract-summary', |
|||
params |
|||
}) |
|||
}, |
|||
// 5.1 获取客户公海分析(按日期)
|
|||
getPoolSummaryByDate: (param: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-pool-summary-by-date', |
|||
params: param |
|||
}) |
|||
}, |
|||
// 5.2 获取客户公海分析(按用户)
|
|||
getPoolSummaryByUser: (param: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-pool-summary-by-user', |
|||
params: param |
|||
}) |
|||
}, |
|||
// 6.1 获取客户成交周期(按日期)
|
|||
getCustomerDealCycleByDate: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-customer-deal-cycle-by-date', |
|||
params |
|||
}) |
|||
}, |
|||
// 6.2 获取客户成交周期(按用户)
|
|||
getCustomerDealCycleByUser: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-customer-deal-cycle-by-user', |
|||
params |
|||
}) |
|||
}, |
|||
// 6.2 获取客户成交周期(按用户)
|
|||
getCustomerDealCycleByArea: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-customer-deal-cycle-by-area', |
|||
params |
|||
}) |
|||
}, |
|||
// 6.2 获取客户成交周期(按用户)
|
|||
getCustomerDealCycleByProduct: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-customer/get-customer-deal-cycle-by-product', |
|||
params |
|||
}) |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface CrmStatisticFunnelRespVO { |
|||
customerCount: number // 客户数
|
|||
businessCount: number // 商机数
|
|||
businessWinCount: number // 赢单数
|
|||
} |
|||
|
|||
export interface CrmStatisticsBusinessSummaryByDateRespVO { |
|||
time: string // 时间
|
|||
businessCreateCount: number // 商机数
|
|||
totalPrice: number | string // 商机金额
|
|||
} |
|||
|
|||
export interface CrmStatisticsBusinessInversionRateSummaryByDateRespVO { |
|||
time: string // 时间
|
|||
businessCount: number // 商机数量
|
|||
businessWinCount: number // 赢单商机数
|
|||
} |
|||
|
|||
// 客户分析 API
|
|||
export const StatisticFunnelApi = { |
|||
// 1. 获取销售漏斗统计数据
|
|||
getFunnelSummary: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-funnel/get-funnel-summary', |
|||
params |
|||
}) |
|||
}, |
|||
// 2. 获取商机结束状态统计
|
|||
getBusinessSummaryByEndStatus: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-funnel/get-business-summary-by-end-status', |
|||
params |
|||
}) |
|||
}, |
|||
// 3. 获取新增商机分析(按日期)
|
|||
getBusinessSummaryByDate: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-funnel/get-business-summary-by-date', |
|||
params |
|||
}) |
|||
}, |
|||
// 4. 获取商机转化率分析(按日期)
|
|||
getBusinessInversionRateSummaryByDate: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-funnel/get-business-inversion-rate-summary-by-date', |
|||
params |
|||
}) |
|||
}, |
|||
// 5. 获取商机列表(按日期)
|
|||
getBusinessPageByDate: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-funnel/get-business-page-by-date', |
|||
params |
|||
}) |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface StatisticsPerformanceRespVO { |
|||
time: string |
|||
currentMonthCount: number |
|||
lastMonthCount: number |
|||
lastYearCount: number |
|||
} |
|||
|
|||
// 排行 API
|
|||
export const StatisticsPerformanceApi = { |
|||
// 员工获得合同金额统计
|
|||
getContractPricePerformance: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-performance/get-contract-price-performance', |
|||
params |
|||
}) |
|||
}, |
|||
// 员工获得回款统计
|
|||
getReceivablePricePerformance: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-performance/get-receivable-price-performance', |
|||
params |
|||
}) |
|||
}, |
|||
//员工获得签约合同数量统计
|
|||
getContractCountPerformance: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-performance/get-contract-count-performance', |
|||
params |
|||
}) |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface CrmStatisticCustomerBaseRespVO { |
|||
customerCount: number |
|||
dealCount: number |
|||
dealPortion: string | number |
|||
} |
|||
|
|||
export interface CrmStatisticCustomerIndustryRespVO extends CrmStatisticCustomerBaseRespVO { |
|||
industryId: number |
|||
industryPortion: string | number |
|||
} |
|||
|
|||
export interface CrmStatisticCustomerSourceRespVO extends CrmStatisticCustomerBaseRespVO { |
|||
source: number |
|||
sourcePortion: string | number |
|||
} |
|||
|
|||
export interface CrmStatisticCustomerLevelRespVO extends CrmStatisticCustomerBaseRespVO { |
|||
level: number |
|||
levelPortion: string | number |
|||
} |
|||
|
|||
export interface CrmStatisticCustomerAreaRespVO extends CrmStatisticCustomerBaseRespVO { |
|||
areaId: number |
|||
areaName: string |
|||
areaPortion: string | number |
|||
} |
|||
|
|||
// 客户分析 API
|
|||
export const StatisticsPortraitApi = { |
|||
// 1. 获取客户行业统计数据
|
|||
getCustomerIndustry: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-portrait/get-customer-industry-summary', |
|||
params |
|||
}) |
|||
}, |
|||
// 2. 获取客户来源统计数据
|
|||
getCustomerSource: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-portrait/get-customer-source-summary', |
|||
params |
|||
}) |
|||
}, |
|||
// 3. 获取客户级别统计数据
|
|||
getCustomerLevel: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-portrait/get-customer-level-summary', |
|||
params |
|||
}) |
|||
}, |
|||
// 4. 获取客户地区统计数据
|
|||
getCustomerArea: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-portrait/get-customer-area-summary', |
|||
params |
|||
}) |
|||
} |
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface StatisticsRankRespVO { |
|||
count: number |
|||
nickname: string |
|||
deptName: string |
|||
} |
|||
|
|||
// 排行 API
|
|||
export const StatisticsRankApi = { |
|||
// 获得合同排行榜
|
|||
getContractPriceRank: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-rank/get-contract-price-rank', |
|||
params |
|||
}) |
|||
}, |
|||
// 获得回款排行榜
|
|||
getReceivablePriceRank: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-rank/get-receivable-price-rank', |
|||
params |
|||
}) |
|||
}, |
|||
// 签约合同排行
|
|||
getContractCountRank: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-rank/get-contract-count-rank', |
|||
params |
|||
}) |
|||
}, |
|||
// 产品销量排行
|
|||
getProductSalesRank: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-rank/get-product-sales-rank', |
|||
params |
|||
}) |
|||
}, |
|||
// 新增客户数排行
|
|||
getCustomerCountRank: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-rank/get-customer-count-rank', |
|||
params |
|||
}) |
|||
}, |
|||
// 新增联系人数排行
|
|||
getContactsCountRank: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-rank/get-contacts-count-rank', |
|||
params |
|||
}) |
|||
}, |
|||
// 跟进次数排行
|
|||
getFollowCountRank: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-rank/get-follow-count-rank', |
|||
params |
|||
}) |
|||
}, |
|||
// 跟进客户数排行
|
|||
getFollowCustomerCountRank: (params: any) => { |
|||
return request.get({ |
|||
url: '/crm/statistics-rank/get-follow-customer-count-rank', |
|||
params |
|||
}) |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 结算账户 VO
|
|||
export interface AccountVO { |
|||
id: number // 结算账户编号
|
|||
no: string // 账户编码
|
|||
remark: string // 备注
|
|||
status: number // 开启状态
|
|||
sort: number // 排序
|
|||
defaultStatus: boolean // 是否默认
|
|||
name: string // 账户名称
|
|||
} |
|||
|
|||
// ERP 结算账户 API
|
|||
export const AccountApi = { |
|||
// 查询结算账户分页
|
|||
getAccountPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/account/page`, params }) |
|||
}, |
|||
|
|||
// 查询结算账户精简列表
|
|||
getAccountSimpleList: async () => { |
|||
return await request.get({ url: `/erp/account/simple-list` }) |
|||
}, |
|||
|
|||
// 查询结算账户详情
|
|||
getAccount: async (id: number) => { |
|||
return await request.get({ url: `/erp/account/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增结算账户
|
|||
createAccount: async (data: AccountVO) => { |
|||
return await request.post({ url: `/erp/account/create`, data }) |
|||
}, |
|||
|
|||
// 修改结算账户
|
|||
updateAccount: async (data: AccountVO) => { |
|||
return await request.put({ url: `/erp/account/update`, data }) |
|||
}, |
|||
|
|||
// 修改结算账户默认状态
|
|||
updateAccountDefaultStatus: async (id: number, defaultStatus: boolean) => { |
|||
return await request.put({ |
|||
url: `/erp/account/update-default-status`, |
|||
params: { |
|||
id, |
|||
defaultStatus |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 删除结算账户
|
|||
deleteAccount: async (id: number) => { |
|||
return await request.delete({ url: `/erp/account/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 导出结算账户 Excel
|
|||
exportAccount: async (params: any) => { |
|||
return await request.download({ url: `/erp/account/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 付款单 VO
|
|||
export interface FinancePaymentVO { |
|||
id: number // 付款单编号
|
|||
no: string // 付款单号
|
|||
supplierId: number // 供应商编号
|
|||
paymentTime: Date // 付款时间
|
|||
totalPrice: number // 合计金额,单位:元
|
|||
status: number // 状态
|
|||
remark: string // 备注
|
|||
} |
|||
|
|||
// ERP 付款单 API
|
|||
export const FinancePaymentApi = { |
|||
// 查询付款单分页
|
|||
getFinancePaymentPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/finance-payment/page`, params }) |
|||
}, |
|||
|
|||
// 查询付款单详情
|
|||
getFinancePayment: async (id: number) => { |
|||
return await request.get({ url: `/erp/finance-payment/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增付款单
|
|||
createFinancePayment: async (data: FinancePaymentVO) => { |
|||
return await request.post({ url: `/erp/finance-payment/create`, data }) |
|||
}, |
|||
|
|||
// 修改付款单
|
|||
updateFinancePayment: async (data: FinancePaymentVO) => { |
|||
return await request.put({ url: `/erp/finance-payment/update`, data }) |
|||
}, |
|||
|
|||
// 更新付款单的状态
|
|||
updateFinancePaymentStatus: async (id: number, status: number) => { |
|||
return await request.put({ |
|||
url: `/erp/finance-payment/update-status`, |
|||
params: { |
|||
id, |
|||
status |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 删除付款单
|
|||
deleteFinancePayment: async (ids: number[]) => { |
|||
return await request.delete({ |
|||
url: `/erp/finance-payment/delete`, |
|||
params: { |
|||
ids: ids.join(',') |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 导出付款单 Excel
|
|||
exportFinancePayment: async (params: any) => { |
|||
return await request.download({ url: `/erp/finance-payment/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 收款单 VO
|
|||
export interface FinanceReceiptVO { |
|||
id: number // 收款单编号
|
|||
no: string // 收款单号
|
|||
customerId: number // 客户编号
|
|||
receiptTime: Date // 收款时间
|
|||
totalPrice: number // 合计金额,单位:元
|
|||
status: number // 状态
|
|||
remark: string // 备注
|
|||
} |
|||
|
|||
// ERP 收款单 API
|
|||
export const FinanceReceiptApi = { |
|||
// 查询收款单分页
|
|||
getFinanceReceiptPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/finance-receipt/page`, params }) |
|||
}, |
|||
|
|||
// 查询收款单详情
|
|||
getFinanceReceipt: async (id: number) => { |
|||
return await request.get({ url: `/erp/finance-receipt/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增收款单
|
|||
createFinanceReceipt: async (data: FinanceReceiptVO) => { |
|||
return await request.post({ url: `/erp/finance-receipt/create`, data }) |
|||
}, |
|||
|
|||
// 修改收款单
|
|||
updateFinanceReceipt: async (data: FinanceReceiptVO) => { |
|||
return await request.put({ url: `/erp/finance-receipt/update`, data }) |
|||
}, |
|||
|
|||
// 更新收款单的状态
|
|||
updateFinanceReceiptStatus: async (id: number, status: number) => { |
|||
return await request.put({ |
|||
url: `/erp/finance-receipt/update-status`, |
|||
params: { |
|||
id, |
|||
status |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 删除收款单
|
|||
deleteFinanceReceipt: async (ids: number[]) => { |
|||
return await request.delete({ |
|||
url: `/erp/finance-receipt/delete`, |
|||
params: { |
|||
ids: ids.join(',') |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 导出收款单 Excel
|
|||
exportFinanceReceipt: async (params: any) => { |
|||
return await request.download({ url: `/erp/finance-receipt/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 产品分类 VO
|
|||
export interface ProductCategoryVO { |
|||
id: number // 分类编号
|
|||
parentId: number // 父分类编号
|
|||
name: string // 分类名称
|
|||
code: string // 分类编码
|
|||
sort: number // 分类排序
|
|||
status: number // 开启状态
|
|||
} |
|||
|
|||
// ERP 产品分类 API
|
|||
export const ProductCategoryApi = { |
|||
// 查询产品分类列表
|
|||
getProductCategoryList: async () => { |
|||
return await request.get({ url: `/erp/product-category/list` }) |
|||
}, |
|||
|
|||
// 查询产品分类精简列表
|
|||
getProductCategorySimpleList: async () => { |
|||
return await request.get({ url: `/erp/product-category/simple-list` }) |
|||
}, |
|||
|
|||
// 查询产品分类详情
|
|||
getProductCategory: async (id: number) => { |
|||
return await request.get({ url: `/erp/product-category/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增产品分类
|
|||
createProductCategory: async (data: ProductCategoryVO) => { |
|||
return await request.post({ url: `/erp/product-category/create`, data }) |
|||
}, |
|||
|
|||
// 修改产品分类
|
|||
updateProductCategory: async (data: ProductCategoryVO) => { |
|||
return await request.put({ url: `/erp/product-category/update`, data }) |
|||
}, |
|||
|
|||
// 删除产品分类
|
|||
deleteProductCategory: async (id: number) => { |
|||
return await request.delete({ url: `/erp/product-category/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 导出产品分类 Excel
|
|||
exportProductCategory: async (params) => { |
|||
return await request.download({ url: `/erp/product-category/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 产品 VO
|
|||
export interface ProductVO { |
|||
id: number // 产品编号
|
|||
name: string // 产品名称
|
|||
barCode: string // 产品条码
|
|||
categoryId: number // 产品类型编号
|
|||
unitId: number // 单位编号
|
|||
unitName?: string // 单位名字
|
|||
status: number // 产品状态
|
|||
standard: string // 产品规格
|
|||
remark: string // 产品备注
|
|||
expiryDay: number // 保质期天数
|
|||
weight: number // 重量(kg)
|
|||
purchasePrice: number // 采购价格,单位:元
|
|||
salePrice: number // 销售价格,单位:元
|
|||
minPrice: number // 最低价格,单位:元
|
|||
} |
|||
|
|||
// ERP 产品 API
|
|||
export const ProductApi = { |
|||
// 查询产品分页
|
|||
getProductPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/product/page`, params }) |
|||
}, |
|||
|
|||
// 查询产品精简列表
|
|||
getProductSimpleList: async () => { |
|||
return await request.get({ url: `/erp/product/simple-list` }) |
|||
}, |
|||
|
|||
// 查询产品详情
|
|||
getProduct: async (id: number) => { |
|||
return await request.get({ url: `/erp/product/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增产品
|
|||
createProduct: async (data: ProductVO) => { |
|||
return await request.post({ url: `/erp/product/create`, data }) |
|||
}, |
|||
|
|||
// 修改产品
|
|||
updateProduct: async (data: ProductVO) => { |
|||
return await request.put({ url: `/erp/product/update`, data }) |
|||
}, |
|||
|
|||
// 删除产品
|
|||
deleteProduct: async (id: number) => { |
|||
return await request.delete({ url: `/erp/product/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 导出产品 Excel
|
|||
exportProduct: async (params) => { |
|||
return await request.download({ url: `/erp/product/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 产品单位 VO
|
|||
export interface ProductUnitVO { |
|||
id: number // 单位编号
|
|||
name: string // 单位名字
|
|||
status: number // 单位状态
|
|||
} |
|||
|
|||
// ERP 产品单位 API
|
|||
export const ProductUnitApi = { |
|||
// 查询产品单位分页
|
|||
getProductUnitPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/product-unit/page`, params }) |
|||
}, |
|||
|
|||
// 查询产品单位精简列表
|
|||
getProductUnitSimpleList: async () => { |
|||
return await request.get({ url: `/erp/product-unit/simple-list` }) |
|||
}, |
|||
|
|||
// 查询产品单位详情
|
|||
getProductUnit: async (id: number) => { |
|||
return await request.get({ url: `/erp/product-unit/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增产品单位
|
|||
createProductUnit: async (data: ProductUnitVO) => { |
|||
return await request.post({ url: `/erp/product-unit/create`, data }) |
|||
}, |
|||
|
|||
// 修改产品单位
|
|||
updateProductUnit: async (data: ProductUnitVO) => { |
|||
return await request.put({ url: `/erp/product-unit/update`, data }) |
|||
}, |
|||
|
|||
// 删除产品单位
|
|||
deleteProductUnit: async (id: number) => { |
|||
return await request.delete({ url: `/erp/product-unit/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 导出产品单位 Excel
|
|||
exportProductUnit: async (params) => { |
|||
return await request.download({ url: `/erp/product-unit/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 采购入库 VO
|
|||
export interface PurchaseInVO { |
|||
id: number // 入库工单编号
|
|||
no: string // 采购入库号
|
|||
customerId: number // 客户编号
|
|||
inTime: Date // 入库时间
|
|||
totalCount: number // 合计数量
|
|||
totalPrice: number // 合计金额,单位:元
|
|||
status: number // 状态
|
|||
remark: string // 备注
|
|||
outCount: number // 采购出库数量
|
|||
returnCount: number // 采购退货数量
|
|||
} |
|||
|
|||
// ERP 采购入库 API
|
|||
export const PurchaseInApi = { |
|||
// 查询采购入库分页
|
|||
getPurchaseInPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/purchase-in/page`, params }) |
|||
}, |
|||
|
|||
// 查询采购入库详情
|
|||
getPurchaseIn: async (id: number) => { |
|||
return await request.get({ url: `/erp/purchase-in/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增采购入库
|
|||
createPurchaseIn: async (data: PurchaseInVO) => { |
|||
return await request.post({ url: `/erp/purchase-in/create`, data }) |
|||
}, |
|||
|
|||
// 修改采购入库
|
|||
updatePurchaseIn: async (data: PurchaseInVO) => { |
|||
return await request.put({ url: `/erp/purchase-in/update`, data }) |
|||
}, |
|||
|
|||
// 更新采购入库的状态
|
|||
updatePurchaseInStatus: async (id: number, status: number) => { |
|||
return await request.put({ |
|||
url: `/erp/purchase-in/update-status`, |
|||
params: { |
|||
id, |
|||
status |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 删除采购入库
|
|||
deletePurchaseIn: async (ids: number[]) => { |
|||
return await request.delete({ |
|||
url: `/erp/purchase-in/delete`, |
|||
params: { |
|||
ids: ids.join(',') |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 导出采购入库 Excel
|
|||
exportPurchaseIn: async (params: any) => { |
|||
return await request.download({ url: `/erp/purchase-in/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 采购订单 VO
|
|||
export interface PurchaseOrderVO { |
|||
id: number // 订单工单编号
|
|||
no: string // 采购订单号
|
|||
customerId: number // 客户编号
|
|||
orderTime: Date // 订单时间
|
|||
totalCount: number // 合计数量
|
|||
totalPrice: number // 合计金额,单位:元
|
|||
status: number // 状态
|
|||
remark: string // 备注
|
|||
outCount: number // 采购出库数量
|
|||
returnCount: number // 采购退货数量
|
|||
} |
|||
|
|||
// ERP 采购订单 API
|
|||
export const PurchaseOrderApi = { |
|||
// 查询采购订单分页
|
|||
getPurchaseOrderPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/purchase-order/page`, params }) |
|||
}, |
|||
|
|||
// 查询采购订单详情
|
|||
getPurchaseOrder: async (id: number) => { |
|||
return await request.get({ url: `/erp/purchase-order/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增采购订单
|
|||
createPurchaseOrder: async (data: PurchaseOrderVO) => { |
|||
return await request.post({ url: `/erp/purchase-order/create`, data }) |
|||
}, |
|||
|
|||
// 修改采购订单
|
|||
updatePurchaseOrder: async (data: PurchaseOrderVO) => { |
|||
return await request.put({ url: `/erp/purchase-order/update`, data }) |
|||
}, |
|||
|
|||
// 更新采购订单的状态
|
|||
updatePurchaseOrderStatus: async (id: number, status: number) => { |
|||
return await request.put({ |
|||
url: `/erp/purchase-order/update-status`, |
|||
params: { |
|||
id, |
|||
status |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 删除采购订单
|
|||
deletePurchaseOrder: async (ids: number[]) => { |
|||
return await request.delete({ |
|||
url: `/erp/purchase-order/delete`, |
|||
params: { |
|||
ids: ids.join(',') |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 导出采购订单 Excel
|
|||
exportPurchaseOrder: async (params: any) => { |
|||
return await request.download({ url: `/erp/purchase-order/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 采购退货 VO
|
|||
export interface PurchaseReturnVO { |
|||
id: number // 采购退货编号
|
|||
no: string // 采购退货号
|
|||
customerId: number // 客户编号
|
|||
returnTime: Date // 退货时间
|
|||
totalCount: number // 合计数量
|
|||
totalPrice: number // 合计金额,单位:元
|
|||
status: number // 状态
|
|||
remark: string // 备注
|
|||
} |
|||
|
|||
// ERP 采购退货 API
|
|||
export const PurchaseReturnApi = { |
|||
// 查询采购退货分页
|
|||
getPurchaseReturnPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/purchase-return/page`, params }) |
|||
}, |
|||
|
|||
// 查询采购退货详情
|
|||
getPurchaseReturn: async (id: number) => { |
|||
return await request.get({ url: `/erp/purchase-return/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增采购退货
|
|||
createPurchaseReturn: async (data: PurchaseReturnVO) => { |
|||
return await request.post({ url: `/erp/purchase-return/create`, data }) |
|||
}, |
|||
|
|||
// 修改采购退货
|
|||
updatePurchaseReturn: async (data: PurchaseReturnVO) => { |
|||
return await request.put({ url: `/erp/purchase-return/update`, data }) |
|||
}, |
|||
|
|||
// 更新采购退货的状态
|
|||
updatePurchaseReturnStatus: async (id: number, status: number) => { |
|||
return await request.put({ |
|||
url: `/erp/purchase-return/update-status`, |
|||
params: { |
|||
id, |
|||
status |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 删除采购退货
|
|||
deletePurchaseReturn: async (ids: number[]) => { |
|||
return await request.delete({ |
|||
url: `/erp/purchase-return/delete`, |
|||
params: { |
|||
ids: ids.join(',') |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 导出采购退货 Excel
|
|||
exportPurchaseReturn: async (params: any) => { |
|||
return await request.download({ url: `/erp/purchase-return/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 供应商 VO
|
|||
export interface SupplierVO { |
|||
id: number // 供应商编号
|
|||
name: string // 供应商名称
|
|||
contact: string // 联系人
|
|||
mobile: string // 手机号码
|
|||
telephone: string // 联系电话
|
|||
email: string // 电子邮箱
|
|||
fax: string // 传真
|
|||
remark: string // 备注
|
|||
status: number // 开启状态
|
|||
sort: number // 排序
|
|||
taxNo: string // 纳税人识别号
|
|||
taxPercent: number // 税率
|
|||
bankName: string // 开户行
|
|||
bankAccount: string // 开户账号
|
|||
bankAddress: string // 开户地址
|
|||
} |
|||
|
|||
// ERP 供应商 API
|
|||
export const SupplierApi = { |
|||
// 查询供应商分页
|
|||
getSupplierPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/supplier/page`, params }) |
|||
}, |
|||
|
|||
// 获得供应商精简列表
|
|||
getSupplierSimpleList: async () => { |
|||
return await request.get({ url: `/erp/supplier/simple-list` }) |
|||
}, |
|||
|
|||
// 查询供应商详情
|
|||
getSupplier: async (id: number) => { |
|||
return await request.get({ url: `/erp/supplier/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增供应商
|
|||
createSupplier: async (data: SupplierVO) => { |
|||
return await request.post({ url: `/erp/supplier/create`, data }) |
|||
}, |
|||
|
|||
// 修改供应商
|
|||
updateSupplier: async (data: SupplierVO) => { |
|||
return await request.put({ url: `/erp/supplier/update`, data }) |
|||
}, |
|||
|
|||
// 删除供应商
|
|||
deleteSupplier: async (id: number) => { |
|||
return await request.delete({ url: `/erp/supplier/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 导出供应商 Excel
|
|||
exportSupplier: async (params) => { |
|||
return await request.download({ url: `/erp/supplier/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 客户 VO
|
|||
export interface CustomerVO { |
|||
id: number // 客户编号
|
|||
name: string // 客户名称
|
|||
contact: string // 联系人
|
|||
mobile: string // 手机号码
|
|||
telephone: string // 联系电话
|
|||
email: string // 电子邮箱
|
|||
fax: string // 传真
|
|||
remark: string // 备注
|
|||
status: number // 开启状态
|
|||
sort: number // 排序
|
|||
taxNo: string // 纳税人识别号
|
|||
taxPercent: number // 税率
|
|||
bankName: string // 开户行
|
|||
bankAccount: string // 开户账号
|
|||
bankAddress: string // 开户地址
|
|||
} |
|||
|
|||
// ERP 客户 API
|
|||
export const CustomerApi = { |
|||
// 查询客户分页
|
|||
getCustomerPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/customer/page`, params }) |
|||
}, |
|||
|
|||
// 查询客户精简列表
|
|||
getCustomerSimpleList: async () => { |
|||
return await request.get({ url: `/erp/customer/simple-list` }) |
|||
}, |
|||
|
|||
// 查询客户详情
|
|||
getCustomer: async (id: number) => { |
|||
return await request.get({ url: `/erp/customer/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增客户
|
|||
createCustomer: async (data: CustomerVO) => { |
|||
return await request.post({ url: `/erp/customer/create`, data }) |
|||
}, |
|||
|
|||
// 修改客户
|
|||
updateCustomer: async (data: CustomerVO) => { |
|||
return await request.put({ url: `/erp/customer/update`, data }) |
|||
}, |
|||
|
|||
// 删除客户
|
|||
deleteCustomer: async (id: number) => { |
|||
return await request.delete({ url: `/erp/customer/delete?id=` + id }) |
|||
}, |
|||
|
|||
// 导出客户 Excel
|
|||
exportCustomer: async (params) => { |
|||
return await request.download({ url: `/erp/customer/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 销售订单 VO
|
|||
export interface SaleOrderVO { |
|||
id: number // 订单工单编号
|
|||
no: string // 销售订单号
|
|||
customerId: number // 客户编号
|
|||
orderTime: Date // 订单时间
|
|||
totalCount: number // 合计数量
|
|||
totalPrice: number // 合计金额,单位:元
|
|||
status: number // 状态
|
|||
remark: string // 备注
|
|||
outCount: number // 销售出库数量
|
|||
returnCount: number // 销售退货数量
|
|||
} |
|||
|
|||
// ERP 销售订单 API
|
|||
export const SaleOrderApi = { |
|||
// 查询销售订单分页
|
|||
getSaleOrderPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/sale-order/page`, params }) |
|||
}, |
|||
|
|||
// 查询销售订单详情
|
|||
getSaleOrder: async (id: number) => { |
|||
return await request.get({ url: `/erp/sale-order/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增销售订单
|
|||
createSaleOrder: async (data: SaleOrderVO) => { |
|||
return await request.post({ url: `/erp/sale-order/create`, data }) |
|||
}, |
|||
|
|||
// 修改销售订单
|
|||
updateSaleOrder: async (data: SaleOrderVO) => { |
|||
return await request.put({ url: `/erp/sale-order/update`, data }) |
|||
}, |
|||
|
|||
// 更新销售订单的状态
|
|||
updateSaleOrderStatus: async (id: number, status: number) => { |
|||
return await request.put({ |
|||
url: `/erp/sale-order/update-status`, |
|||
params: { |
|||
id, |
|||
status |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 删除销售订单
|
|||
deleteSaleOrder: async (ids: number[]) => { |
|||
return await request.delete({ |
|||
url: `/erp/sale-order/delete`, |
|||
params: { |
|||
ids: ids.join(',') |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 导出销售订单 Excel
|
|||
exportSaleOrder: async (params: any) => { |
|||
return await request.download({ url: `/erp/sale-order/export-excel`, params }) |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
// ERP 销售出库 VO
|
|||
export interface SaleOutVO { |
|||
id: number // 销售出库编号
|
|||
no: string // 销售出库号
|
|||
customerId: number // 客户编号
|
|||
outTime: Date // 出库时间
|
|||
totalCount: number // 合计数量
|
|||
totalPrice: number // 合计金额,单位:元
|
|||
status: number // 状态
|
|||
remark: string // 备注
|
|||
} |
|||
|
|||
// ERP 销售出库 API
|
|||
export const SaleOutApi = { |
|||
// 查询销售出库分页
|
|||
getSaleOutPage: async (params: any) => { |
|||
return await request.get({ url: `/erp/sale-out/page`, params }) |
|||
}, |
|||
|
|||
// 查询销售出库详情
|
|||
getSaleOut: async (id: number) => { |
|||
return await request.get({ url: `/erp/sale-out/get?id=` + id }) |
|||
}, |
|||
|
|||
// 新增销售出库
|
|||
createSaleOut: async (data: SaleOutVO) => { |
|||
return await request.post({ url: `/erp/sale-out/create`, data }) |
|||
}, |
|||
|
|||
// 修改销售出库
|
|||
updateSaleOut: async (data: SaleOutVO) => { |
|||
return await request.put({ url: `/erp/sale-out/update`, data }) |
|||
}, |
|||
|
|||
// 更新销售出库的状态
|
|||
updateSaleOutStatus: async (id: number, status: number) => { |
|||
return await request.put({ |
|||
url: `/erp/sale-out/update-status`, |
|||
params: { |
|||
id, |
|||
status |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 删除销售出库
|
|||
deleteSaleOut: async (ids: number[]) => { |
|||
return await request.delete({ |
|||
url: `/erp/sale-out/delete`, |
|||
params: { |
|||
ids: ids.join(',') |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 导出销售出库 Excel
|
|||
exportSaleOut: async (params: any) => { |
|||
return await request.download({ url: `/erp/sale-out/export-excel`, params }) |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue