zhouyuhao 1 vuosi sitten
commit
1883a1c04c
100 muutettua tiedostoa jossa 8128 lisäystä ja 0 poistoa
  1. 16 0
      .eslintrc.cjs
  2. 33 0
      .gitignore
  3. 8 0
      .prettierrc.json
  4. 7 0
      .vscode/extensions.json
  5. 39 0
      README.md
  6. 1 0
      env.d.ts
  7. 13 0
      index.html
  8. 68 0
      package.json
  9. BIN
      public/favicon.ico
  10. 10 0
      src/App.vue
  11. 22 0
      src/api/index.ts
  12. 92 0
      src/api/module/booking.ts
  13. 26 0
      src/api/module/common.ts
  14. 49 0
      src/api/module/tracking.ts
  15. 74 0
      src/assets/base.css
  16. 1 0
      src/assets/logo.svg
  17. 19 0
      src/assets/main.css
  18. 69 0
      src/auto-imports.d.ts
  19. 1 0
      src/components/AutoComplete/index.ts
  20. 241 0
      src/components/AutoComplete/src/AutoComplete.vue
  21. 1 0
      src/components/AutoSelect/index.ts
  22. 121 0
      src/components/AutoSelect/src/AutoSelect.vue
  23. 1 0
      src/components/ContainerStatus/index.ts
  24. 125 0
      src/components/ContainerStatus/src/ContainerStatus.vue
  25. 1 0
      src/components/CustomizeColumns/index.ts
  26. 762 0
      src/components/CustomizeColumns/src/CustomizeColumns.vue
  27. 1 0
      src/components/DateRange/index.ts
  28. 295 0
      src/components/DateRange/src/DateRange.vue
  29. 135 0
      src/components/DateRange/src/components/CalendarDate.vue
  30. 1 0
      src/components/FliterTags/index.ts
  31. 165 0
      src/components/FliterTags/src/FilterTags.vue
  32. 1 0
      src/components/Icon/index.ts
  33. 63 0
      src/components/Icon/src/IconView.vue
  34. 1 0
      src/components/IconDropDown/index.ts
  35. 18 0
      src/components/IconDropDown/src/IconDropDown.vue
  36. 1 0
      src/components/MoreFilters/index.ts
  37. 816 0
      src/components/MoreFilters/src/MoreFilters.vue
  38. 283 0
      src/components/MoreFilters/src/components/SelectValue.vue
  39. 111 0
      src/components/ScoringGrade/components/DialogColorful.vue
  40. 218 0
      src/components/ScoringGrade/components/DialogUe.vue
  41. 1 0
      src/components/ScoringGrade/index.ts
  42. 293 0
      src/components/ScoringGrade/src/ScoringGrade.vue
  43. 1 0
      src/components/SeeAllIcon/index.ts
  44. 45 0
      src/components/SeeAllIcon/src/SeeAllIcon.vue
  45. 1 0
      src/components/SelectTable/index.ts
  46. 114 0
      src/components/SelectTable/src/SelectTable copy.vue
  47. 341 0
      src/components/SelectTable/src/SelectTable.vue
  48. 1 0
      src/components/SelectTableSelect/index.ts
  49. 240 0
      src/components/SelectTableSelect/src/SelectTableSelect.vue
  50. 1 0
      src/components/ShipmentStatus/index.ts
  51. 205 0
      src/components/ShipmentStatus/src/ShipmentStatus.vue
  52. 1 0
      src/components/TransportMode/index.ts
  53. 299 0
      src/components/TransportMode/src/TransportMode.vue
  54. 1 0
      src/components/VBox/index.ts
  55. 159 0
      src/components/VBox/src/VBox.vue
  56. 1 0
      src/components/VBox_Dashboard/index.ts
  57. 169 0
      src/components/VBox_Dashboard/src/VBox_Dashboard.vue
  58. 1 0
      src/components/VBreadcrumd/index.ts
  59. 38 0
      src/components/VBreadcrumd/src/VBreadcrumd.vue
  60. 0 0
      src/components/VEmpty/index.ts
  61. 49 0
      src/components/VEmpty/src/VEmpty.vue
  62. BIN
      src/components/VEmpty/src/images/default_image.png
  63. 1 0
      src/components/VLoading/index.ts
  64. 74 0
      src/components/VLoading/src/VLoading.vue
  65. BIN
      src/components/VLoading/src/images/icon_loading.png
  66. 1 0
      src/components/VTag/index.ts
  67. 120 0
      src/components/VTag/src/VTag.vue
  68. 1 0
      src/components/VerrifyInformation/index.ts
  69. 18 0
      src/components/VerrifyInformation/src/VerrifyInformation.vue
  70. 7 0
      src/components/icons/IconCommunity.vue
  71. 7 0
      src/components/icons/IconDocumentation.vue
  72. 7 0
      src/components/icons/IconEcosystem.vue
  73. 7 0
      src/components/icons/IconSupport.vue
  74. 19 0
      src/components/icons/IconTooling.vue
  75. 1 0
      src/components/selectAutoSelect/index.ts
  76. 286 0
      src/components/selectAutoSelect/src/selectAutoSelect.vue
  77. 83 0
      src/directive/VLoading.ts
  78. 67 0
      src/hooks/calculatingHeight.ts
  79. 40 0
      src/hooks/rowClickStyle.ts
  80. 1 0
      src/icons/icon_bold_b.svg
  81. 3 0
      src/icons/icon_date_b.svg
  82. 4 0
      src/icons/icon_logo.svg
  83. 1 0
      src/icons/icon_quotes_b.svg
  84. 1 0
      src/icons/icon_redo_b.svg
  85. 1 0
      src/icons/icon_revoke__b.svg
  86. 1 0
      src/icons/icon_underline_b.svg
  87. 44 0
      src/main.ts
  88. 80 0
      src/router/index.ts
  89. 1 0
      src/shims-vue.d.ts
  90. 4 0
      src/stores/index.ts
  91. 8 0
      src/stores/modules/BookingData.ts
  92. 28 0
      src/stores/modules/parentPath.ts
  93. 66 0
      src/styles/Antdui.scss
  94. 526 0
      src/styles/elementui.scss
  95. BIN
      src/styles/fonts/Lato-Regular.ttf
  96. BIN
      src/styles/fonts/Open-Sans-2.ttf
  97. 700 0
      src/styles/icons/iconfont.css
  98. 0 0
      src/styles/icons/iconfont.js
  99. 50 0
      src/styles/icons/iconfont.svg
  100. BIN
      src/styles/icons/iconfont.ttf

+ 16 - 0
.eslintrc.cjs

@@ -0,0 +1,16 @@
+/* eslint-env node */
+require('@rushstack/eslint-patch/modern-module-resolution')
+
+module.exports = {
+  root: true,
+  extends: [
+    'plugin:vue/vue3-essential',
+    'eslint:recommended',
+    '@vue/eslint-config-typescript',
+    '@vue/eslint-config-prettier/skip-formatting'
+  ],
+  parser: 'vue-eslint-parser',
+  parserOptions: {
+    ecmaVersion: 'latest'
+  }
+}

+ 33 - 0
.gitignore

@@ -0,0 +1,33 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+dist
+dist-ssr
+coverage
+*.local
+components.d.ts
+package-lock.json
+pnpm-lock.yaml
+
+/cypress/videos/
+/cypress/screenshots/
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+*.tsbuildinfo

+ 8 - 0
.prettierrc.json

@@ -0,0 +1,8 @@
+{
+  "$schema": "https://json.schemastore.org/prettierrc",
+  "semi": false,
+  "tabWidth": 2,
+  "singleQuote": true,
+  "printWidth": 100,
+  "trailingComma": "none"
+}

+ 7 - 0
.vscode/extensions.json

@@ -0,0 +1,7 @@
+{
+  "recommendations": [
+    "Vue.volar",
+    "dbaeumer.vscode-eslint",
+    "esbenp.prettier-vscode"
+  ]
+}

+ 39 - 0
README.md

@@ -0,0 +1,39 @@
+# online-optmize
+
+This template should help get you started developing with Vue 3 in Vite.
+
+## Recommended IDE Setup
+
+[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
+
+## Type Support for `.vue` Imports in TS
+
+TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
+
+## Customize configuration
+
+See [Vite Configuration Reference](https://vitejs.dev/config/).
+
+## Project Setup
+
+```sh
+pnpm install
+```
+
+### Compile and Hot-Reload for Development
+
+```sh
+pnpm dev
+```
+
+### Type-Check, Compile and Minify for Production
+
+```sh
+pnpm build
+```
+
+### Lint with [ESLint](https://eslint.org/)
+
+```sh
+pnpm lint
+```

+ 1 - 0
env.d.ts

@@ -0,0 +1 @@
+/// <reference types="vite/client" />

+ 13 - 0
index.html

@@ -0,0 +1,13 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" href="/favicon.ico" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>online</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>

+ 68 - 0
package.json

@@ -0,0 +1,68 @@
+{
+  "name": "online-optmize",
+  "version": "0.0.0",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "run-p type-check \"build-only {@}\" --",
+    "preview": "vite preview",
+    "build-only": "vite build",
+    "type-check": "vue-tsc --build --force",
+    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
+    "format": "prettier --write src/"
+  },
+  "dependencies": {
+    "@element-plus/icons-vue": "^2.3.1",
+    "@wangeditor/editor": "^5.1.23",
+    "@wangeditor/editor-for-vue": "^5.1.12",
+    "ant-design-vue": "^4.2.3",
+    "axios": "^1.7.5",
+    "dayjs": "^1.11.13",
+    "echarts": "^5.5.1",
+    "element-plus": "^2.8.1",
+    "exceljs": "^4.4.0",
+    "js-md5": "^0.8.3",
+    "lodash": "^4.17.21",
+    "mitt": "^3.0.1",
+    "moment": "^2.30.1",
+    "pinia": "^2.2.2",
+    "vue": "^3.4.29",
+    "vue-draggable-plus": "^0.5.3",
+    "vue-router": "^4.3.3",
+    "vuedraggable": "^2.24.3",
+    "vxe-pc-ui": "^4.1.7",
+    "vxe-table": "^4.7.70",
+    "vxe-table-plugin-export-xlsx": "^4.0.5",
+    "xe-clipboard": "^1.10.2"
+  },
+  "devDependencies": {
+    "@rushstack/eslint-patch": "^1.8.0",
+    "@tsconfig/node20": "^20.1.4",
+    "@types/lodash": "^4.17.7",
+    "@types/node": "^20.14.5",
+    "@vitejs/plugin-vue": "^5.0.5",
+    "@vue/eslint-config-prettier": "^9.0.0",
+    "@vue/eslint-config-typescript": "^13.0.0",
+    "@vue/tsconfig": "^0.5.1",
+    "autoprefixer": "^10.4.20",
+    "eslint": "^8.57.0",
+    "eslint-plugin-vue": "^9.23.0",
+    "npm-run-all2": "^6.2.0",
+    "postcss": "^8.4.41",
+    "postcss-loader": "^8.1.1",
+    "prettier": "^3.2.5",
+    "sass": "^1.77.8",
+    "typescript": "~5.4.0",
+    "unplugin-auto-import": "^0.18.2",
+    "unplugin-icons": "^0.19.2",
+    "unplugin-vue-components": "^0.27.4",
+    "vite": "^5.3.1",
+    "vue-tsc": "^2.0.21"
+  },
+  "postcss": {
+    "plugins": {
+      "autoprefixer": {}
+    }
+  }
+}

BIN
public/favicon.ico


+ 10 - 0
src/App.vue

@@ -0,0 +1,10 @@
+<script setup lang="ts">
+import { RouterLink, RouterView } from 'vue-router'
+import HelloWorld from './components/HelloWorld.vue'
+</script>
+
+<template>
+  <RouterView />
+</template>
+
+<style scoped></style>

+ 22 - 0
src/api/index.ts

@@ -0,0 +1,22 @@
+import * as booking from './module/booking'
+import * as tracking from './module/tracking'
+import * as common from './module/common'
+/**
+ * api 对象接口定义
+ */
+function generateApiMap(maps: any) {
+  const methodMap: any = {}
+  for (const key in maps) {
+    methodMap[key] = maps[key]
+  }
+  return methodMap
+}
+
+const apis = generateApiMap({
+  ...booking,
+  ...tracking,
+  ...common
+})
+export default {
+  ...apis // 取出所有可遍历属性赋值在新的对象上
+}

+ 92 - 0
src/api/module/booking.ts

@@ -0,0 +1,92 @@
+import HttpAxios from '@/utils/axios'
+
+const baseUrl = 'http://localhost/api/Customer_Service_Online/main_new_version.php'
+
+/**
+ * Booking首页表格列数据
+ */
+export const getBookingTableColumns = (params: any, config: any) => {
+  return HttpAxios.get(
+    `${baseUrl}`,
+    {
+      action: 'ocean_booking',
+      ...params
+    },
+    config
+  )
+}
+
+/**
+ * 获取Booking首页表格数据
+ */
+export const getBookingTableData = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'ocean_booking',
+      operate: 'search',
+      _ntype: 'ocean_booking',
+      ...params
+    },
+    config
+  )
+}
+
+/**
+ * 获取Booking详情页数据
+ */
+export const getBookingDetail = (params: any, config: any) => {
+  return HttpAxios.get(
+    `${baseUrl}`,
+    {
+      action: 'ocean_booking',
+      operate: 'detail',
+      _schemas: 'public',
+      ...params
+    },
+    config
+  )
+}
+
+/**
+ * 获取Booking详情页发送邮件
+ */
+export const bookingSendEmail = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'ocean_booking',
+      operate: 'save_communication',
+      ...params
+    },
+    config
+  )
+}
+/**
+ * 获取自动完成列表
+ */
+export const getMoreFiltersData = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'ajax',
+      operate: 'autody',
+      ...params
+    },
+    config
+  )
+}
+/**
+ * 获取table自动完成列表
+ */
+export const getMoreFiltersTableData = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'ajax',
+      operate: 'autoport',
+      ...params
+    },
+    config
+  )
+}

+ 26 - 0
src/api/module/common.ts

@@ -0,0 +1,26 @@
+import HttpAxios from '@/utils/axios'
+
+const baseUrl = 'http://localhost/api/Customer_Service_Online/main_new_version.php'
+
+/**
+ * 获取表格定制列功能数据
+ */
+export const getTableSettingColumns = (params: any, config: any) => {
+  return HttpAxios.get(`${baseUrl}`, params, config)
+}
+
+/**
+ * 保存表格定制列数据
+ */
+export const saveTableSettingColumns = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'ajax',
+      operate: 'save_setting_display',
+      model_name: 'Booking_Search',
+      ...params
+    },
+    config
+  )
+}

+ 49 - 0
src/api/module/tracking.ts

@@ -0,0 +1,49 @@
+import HttpAxios from '@/utils/axios'
+
+const baseUrl = 'http://localhost/api/Customer_Service_Online/main_new_version.php'
+
+/**
+ * Tracking首页表格列数据
+ */
+export const getTrackingTableColumns = (params: any, config: any) => {
+  return HttpAxios.get(
+    `${baseUrl}`,
+    {
+      action: 'ocean_order',
+      ...params
+    },
+    config
+  )
+}
+
+/**
+ * 获取Tracking首页表格数据
+ */
+export const getTrackingTableData = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'ocean_order',
+      operate: 'search',
+      _ntype: 'ocean_order',
+      ...params
+    },
+    config
+  )
+}
+
+/**
+ * 获取Tracking详情页数据
+ */
+export const getTrackingDetail = (params: any, config: any) => {
+  return HttpAxios.get(
+    `${baseUrl}`,
+    {
+      action: 'ocean_order',
+      operate: 'detail',
+      _schemas: 'public',
+      ...params
+    },
+    config
+  )
+}

+ 74 - 0
src/assets/base.css

@@ -0,0 +1,74 @@
+/* color palette from <https://github.com/vuejs/theme> */
+:root {
+  --vt-c-white: #ffffff;
+  --vt-c-white-soft: #f8f8f8;
+  --vt-c-white-mute: #f2f2f2;
+
+  --vt-c-black: #181818;
+  --vt-c-black-soft: #222222;
+  --vt-c-black-mute: #282828;
+
+  --vt-c-indigo: #2c3e50;
+
+  --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
+  --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
+  --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
+  --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
+
+  --vt-c-text-light-1: var(--vt-c-indigo);
+  --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
+  --vt-c-text-dark-1: var(--vt-c-white);
+  --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
+}
+
+/* semantic color variables for this project */
+:root {
+  --color-background: var(--vt-c-white);
+  --color-background-soft: var(--vt-c-white-soft);
+  --color-background-mute: var(--vt-c-white-mute);
+
+  --color-border: var(--vt-c-divider-light-2);
+  --color-border-hover: var(--vt-c-divider-light-1);
+
+  --color-heading: var(--vt-c-text-light-1);
+  --color-text: var(--vt-c-text-light-1);
+
+  --section-gap: 160px;
+}
+
+@media (prefers-color-scheme: dark) {
+  :root {
+    --color-background: var(--vt-c-black);
+    --color-background-soft: var(--vt-c-black-soft);
+    --color-background-mute: var(--vt-c-black-mute);
+
+    --color-border: var(--vt-c-divider-dark-2);
+    --color-border-hover: var(--vt-c-divider-dark-1);
+
+    --color-heading: var(--vt-c-text-dark-1);
+    --color-text: var(--vt-c-text-dark-2);
+  }
+}
+
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+  margin: 0;
+  font-weight: normal;
+}
+
+body {
+  min-height: 100vh;
+  overflow-x: hidden;
+  color: var(--color-text);
+  background: var(--color-background);
+  transition:
+    color 0.5s,
+    background-color 0.5s;
+  line-height: 1.6;
+
+  text-rendering: optimizeLegibility;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}

+ 1 - 0
src/assets/logo.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

+ 19 - 0
src/assets/main.css

@@ -0,0 +1,19 @@
+@import './base.css';
+
+#app {
+  max-width: 100%;
+  height: 100%;
+  font-weight: normal;
+}
+
+/* scroll bar */
+::-webkit-scrollbar {
+  width: 8px;
+  height: 8px;
+  /* background-color: white; */
+}
+::-webkit-scrollbar-thumb {
+  background-color: #dddee0;
+  border-radius: 20px;
+  box-shadow: inset 0 0 0 white;
+}

+ 69 - 0
src/auto-imports.d.ts

@@ -0,0 +1,69 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// noinspection JSUnusedGlobalSymbols
+// Generated by unplugin-auto-import
+export {}
+declare global {
+  const $api: typeof import('@/api/index')['default']
+  const EffectScope: typeof import('vue')['EffectScope']
+  const ElMessage: typeof import('element-plus/es')['ElMessage']
+  const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
+  const computed: typeof import('vue')['computed']
+  const createApp: typeof import('vue')['createApp']
+  const customRef: typeof import('vue')['customRef']
+  const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
+  const defineComponent: typeof import('vue')['defineComponent']
+  const effectScope: typeof import('vue')['effectScope']
+  const getCurrentInstance: typeof import('vue')['getCurrentInstance']
+  const getCurrentScope: typeof import('vue')['getCurrentScope']
+  const h: typeof import('vue')['h']
+  const inject: typeof import('vue')['inject']
+  const isProxy: typeof import('vue')['isProxy']
+  const isReactive: typeof import('vue')['isReactive']
+  const isReadonly: typeof import('vue')['isReadonly']
+  const isRef: typeof import('vue')['isRef']
+  const markRaw: typeof import('vue')['markRaw']
+  const nextTick: typeof import('vue')['nextTick']
+  const onActivated: typeof import('vue')['onActivated']
+  const onBeforeMount: typeof import('vue')['onBeforeMount']
+  const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
+  const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
+  const onDeactivated: typeof import('vue')['onDeactivated']
+  const onErrorCaptured: typeof import('vue')['onErrorCaptured']
+  const onMounted: typeof import('vue')['onMounted']
+  const onRenderTracked: typeof import('vue')['onRenderTracked']
+  const onRenderTriggered: typeof import('vue')['onRenderTriggered']
+  const onScopeDispose: typeof import('vue')['onScopeDispose']
+  const onServerPrefetch: typeof import('vue')['onServerPrefetch']
+  const onUnmounted: typeof import('vue')['onUnmounted']
+  const onUpdated: typeof import('vue')['onUpdated']
+  const provide: typeof import('vue')['provide']
+  const reactive: typeof import('vue')['reactive']
+  const readonly: typeof import('vue')['readonly']
+  const ref: typeof import('vue')['ref']
+  const resolveComponent: typeof import('vue')['resolveComponent']
+  const shallowReactive: typeof import('vue')['shallowReactive']
+  const shallowReadonly: typeof import('vue')['shallowReadonly']
+  const shallowRef: typeof import('vue')['shallowRef']
+  const toRaw: typeof import('vue')['toRaw']
+  const toRef: typeof import('vue')['toRef']
+  const toRefs: typeof import('vue')['toRefs']
+  const toValue: typeof import('vue')['toValue']
+  const triggerRef: typeof import('vue')['triggerRef']
+  const unref: typeof import('vue')['unref']
+  const useAttrs: typeof import('vue')['useAttrs']
+  const useCssModule: typeof import('vue')['useCssModule']
+  const useCssVars: typeof import('vue')['useCssVars']
+  const useSlots: typeof import('vue')['useSlots']
+  const watch: typeof import('vue')['watch']
+  const watchEffect: typeof import('vue')['watchEffect']
+  const watchPostEffect: typeof import('vue')['watchPostEffect']
+  const watchSyncEffect: typeof import('vue')['watchSyncEffect']
+}
+// for type re-export
+declare global {
+  // @ts-ignore
+  export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
+  import('vue')
+}

+ 1 - 0
src/components/AutoComplete/index.ts

@@ -0,0 +1 @@
+export { default } from './src/AutoComplete.vue'

+ 241 - 0
src/components/AutoComplete/src/AutoComplete.vue

@@ -0,0 +1,241 @@
+<script setup lang="ts" name="SelTable">
+import _ from 'lodash'
+import { reactive, ref, onMounted, watch } from 'vue'
+
+const emit = defineEmits(['check', 'input'])
+const props = defineProps({
+  poverWidth: {
+    type: Number,
+    default: 380
+  },
+  searchInput: {
+    type: String,
+    default: ''
+  }
+})
+const searchVal = ref(props.searchInput)
+watch(
+  () => props.searchInput,
+  (current) => {
+    searchVal.value = current
+  }
+)
+// 响应数据
+const state: any = reactive({
+  // searchVal: '',
+  poverShow: false,
+  currentPage: 1,
+  pageSize: 10,
+  total: 6,
+  activeRowIndex: '',
+  tableData: [
+    {
+      Country: 'China',
+      City: 'Shenzhen',
+      id: 1,
+      Uncode: 'CNSZX'
+    },
+    {
+      Country: 'China',
+      City: 'Beijing',
+      id: 2,
+      Uncode: 'CNBJX'
+    },
+    {
+      Country: 'JaPan',
+      id: 3,
+      City: 'Tokyo',
+      Uncode: 'JPARI'
+    },
+    {
+      Country: 'Germany',
+      id: 4,
+      City: 'Berlin',
+      Uncode: 'DEBER'
+    },
+    {
+      Country: 'France',
+      City: 'Paris',
+      id: 5,
+      Uncode: 'FRCDG'
+    },
+    {
+      Country: 'Italy',
+      City: 'Rome',
+      id: 6,
+      Uncode: 'ITCIA'
+    },
+    {
+      Country: 'Italy',
+      City: 'Rome',
+      id: 7,
+      Uncode: 'ITCIA'
+    },
+    {
+      Country: 'Italy',
+      City: 'Rome',
+      id: 8,
+      Uncode: 'ITCIA'
+    },
+    {
+      Country: 'Italy',
+      City: 'Rome',
+      id: 9,
+      Uncode: 'ITCIA'
+    },
+    {
+      Country: 'Italy',
+      City: 'Rome',
+      id: 10,
+      Uncode: 'ITCIA'
+    },
+    {
+      Country: 'Italy',
+      City: 'Rome',
+      id: 11,
+      Uncode: 'ITCIA'
+    }
+  ],
+  copyData: [],
+  loading: false
+})
+
+// 模拟搜索 复制一份数据给copyData,数据来源于接口 直接删除此代码
+onMounted(() => {
+  state.copyData = state.tableData
+  handleSearch()
+})
+
+// 点击行
+const handleRowClick = (row: { id: number; City: string }) => {
+  state.poverShow = false
+  searchVal.value = row.City
+  state.activeRowIndex = row.id
+  // 将点击行传给父级
+  emit('check', row)
+}
+// 搜索 模拟,正常请求接口
+const handleSearch = _.debounce(() => {
+  // 模拟请求,正常将搜索文字传给后端 请求接口 重新赋值
+  state.loading = true
+  emit('input', searchVal.value)
+  setTimeout(() => {
+    const filterList = state.copyData.filter((p: any) => {
+      return (
+        p.Country.indexOf(searchVal.value) > -1 ||
+        p.City.indexOf(searchVal.value) > -1 ||
+        p.Uncode.indexOf(searchVal.value) > -1
+      )
+    })
+    state.tableData = filterList
+    state.total = filterList.length
+    state.loading = false
+  }, 800)
+}, 500)
+// 分页 请求接口
+const handleCurrentChange = (val: number) => {
+  console.log(`current page: ${val}`)
+}
+</script>
+<template>
+  <div>
+    <el-popover
+      v-model:visible="state.poverShow"
+      placement="bottom-start"
+      :teleported="false"
+      :width="props.poverWidth"
+      trigger="click"
+    >
+      <template #reference>
+        <el-input
+          v-model="searchVal"
+          placeholder="Please input country/city/uncode"
+          @input="handleSearch"
+          @click="handleSearch"
+        >
+          <template #suffix>
+            <el-icon :class="state.poverShow ? 'reverse' : ''"><CaretBottom /></el-icon>
+          </template>
+        </el-input>
+      </template>
+      <el-table
+        :data="state.tableData"
+        border
+        stripe
+        v-loading="state.loading"
+        @row-click="handleRowClick"
+        header-row-class-name="cus-header"
+      >
+        <el-table-column width="120" property="Country" label="Country" />
+        <el-table-column width="120" property="City" label="City" />
+        <el-table-column min-width="120" property="Uncode" label="Uncode" />
+      </el-table>
+      <div class="pagination">
+        <span>Total {{ state.total }}</span>
+        <el-pagination
+          v-model:currentPage="state.currentPage"
+          v-model:page-size="state.pageSize"
+          size="small"
+          layout="prev, pager, next"
+          :total="state.total"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-popover>
+  </div>
+</template>
+
+<style scoped lang="scss">
+:deep(.el-input) {
+  input {
+    cursor: pointer;
+  }
+  .el-input__suffix-inner {
+    i {
+      transition: all 0.3s;
+    }
+    .reverse {
+      transform: rotate(-180deg);
+    }
+  }
+  .el-input__wrapper.is-focus {
+    box-shadow: 0 0 0 1px #ffbc79 inset !important;
+  }
+}
+:deep(.cus-header) th {
+  background-color: var(--color-table-header-bg) !important;
+}
+:deep(.el-table__row) {
+  td {
+    cursor: pointer;
+  }
+}
+:deep(.el-table__row:not(.current-row):hover) {
+  td {
+    background-color: #fff1e6 !important;
+  }
+}
+:deep(.current-row) {
+  td {
+    background-color: #ffe3cd !important;
+  }
+}
+.pagination {
+  display: flex;
+  align-items: center;
+  height: 40px;
+  justify-content: space-between;
+  padding: 0 12px 0 8px;
+  > span {
+    font-size: 13px;
+  }
+}
+:deep(.el-popper) {
+  border-radius: 12px !important;
+}
+:deep(.el-pagination) {
+  .is-active {
+    color: #b57b32 !important;
+  }
+}
+</style>

+ 1 - 0
src/components/AutoSelect/index.ts

@@ -0,0 +1 @@
+export { default } from './src/AutoSelect.vue'

+ 121 - 0
src/components/AutoSelect/src/AutoSelect.vue

@@ -0,0 +1,121 @@
+<script setup lang="ts">
+import { ref, watch } from 'vue'
+
+const props = defineProps({
+  ASPlaceholder: {
+    type: String
+  },
+  ASValue: {
+    type: Array
+  },
+  ASisDisabled: {
+    type: Boolean
+  },
+  ASType: {
+    type: String
+  }
+})
+
+interface ListItem {
+  value: string
+  label: string
+}
+
+const list = ref<ListItem[]>([])
+const options = ref<ListItem[]>([])
+const value = ref(props.ASValue)
+const type = ref(props.ASType)
+const loading = ref(false)
+watch(
+  () => props.ASValue,
+  (current) => {
+    value.value = current
+  }
+)
+const remoteMethod = (query: string) => {
+  if (query) {
+    loading.value = true
+    setTimeout(() => {
+      $api
+        .getMoreFiltersData({
+          term: query,
+          type: type.value
+        })
+        .then((res: any) => {
+          console.log(res)
+          loading.value = false
+          if (res.code == 200) {
+            list.value = res.data.map((item: any) => {
+              return { value: item, label: item }
+            })
+            options.value = list.value.filter((item) => {
+              return item.label.toLowerCase().includes(query.toLowerCase())
+            })
+          }
+        })
+    }, 200)
+  } else {
+    options.value = []
+  }
+}
+const emit = defineEmits(['changeAutoSelect'])
+// 选中改变
+const changeAutoSelect = () => {
+  emit('changeAutoSelect', value)
+}
+// 清除警告样式
+const removeClass = () => {
+  const input_change = document.getElementsByClassName('input_change')
+  if (input_change.length) {
+    if (input_change[0].classList.value.indexOf('AlertInput') != -1) {
+      input_change[0].classList.remove('AlertInput')
+    }
+  }
+}
+</script>
+<template>
+  <div>
+    <el-select
+      v-model="value"
+      multiple
+      filterable
+      remote
+      @change="changeAutoSelect"
+      :reserve-keyword="false"
+      :placeholder="props.ASPlaceholder"
+      collapse-tags
+      @focus="removeClass"
+      :disabled="props.ASisDisabled"
+      collapse-tags-tooltip
+      :max-collapse-tags="3"
+      :remote-method="remoteMethod"
+      :loading="loading"
+    >
+      <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
+        <el-checkbox :checked="value?.includes(item.value)"></el-checkbox>
+        <div class="label">{{ item.value }}</div>
+      </el-option>
+    </el-select>
+  </div>
+</template>
+<style lang="scss" scoped>
+.el-select-dropdown__item.is-selected {
+  background-color: transparent;
+  div {
+    color: var(--badge__content--warning);
+  }
+}
+.el-select-dropdown__item {
+  padding-left: 7.7px;
+  display: flex;
+  align-items: center;
+}
+.label {
+  margin-left: 8px;
+}
+.el-select-dropdown__item.is-hovering {
+  div {
+    color: var(--badge__content--warning);
+  }
+}
+</style>

+ 1 - 0
src/components/ContainerStatus/index.ts

@@ -0,0 +1 @@
+export { default } from './src/ContainerStatus.vue'

+ 125 - 0
src/components/ContainerStatus/src/ContainerStatus.vue

@@ -0,0 +1,125 @@
+<script setup lang="ts">
+import dayjs from 'dayjs'
+
+const props = defineProps({
+  data: Object
+})
+
+const containerStatusData: any = ref([
+  {
+    title: 'Empty Equipment Dispatched',
+    date: 'May-31-2024 10:03(GMT+02)',
+    country: 'CN,SHK'
+  },
+  {
+    title: 'In-Gate',
+    date: 'May-31-2024 10:03(GMT+02)',
+    country: 'CN,SHK'
+  },
+  {
+    title: 'Loaded On Vessel',
+    date: 'Jun-05-2024 10:03(GMT+02)',
+    country: 'CN,SHK'
+  },
+  {
+    title: 'Vessel Departure',
+    date: 'Jun-06-2024 10:03(GMT+02)',
+    country: 'CN,SHK'
+  },
+  {
+    title: 'Vessel Arrival',
+    date: 'Jun-07-2024 14:00(GMT+02)',
+    country: 'ES,BCN'
+  }
+])
+watch(
+  () => props.data,
+  (newVal) => {
+    if (newVal) {
+      containerStatusData.value = newVal[0].content
+    } else {
+      containerStatusData.value = []
+    }
+  },
+  {
+    immediate: true,
+    deep: true
+  }
+)
+
+const formatDate = (date: string) => {
+  return date ? dayjs(date).format('MMM-DD-YYYY HH:mm [(GMT]Z[)]') : '--'
+}
+</script>
+
+<template>
+  <div class="container-status">
+    <div class="step-item" v-for="(item, index) in containerStatusData" :key="item.title">
+      <div class="step-data">
+        <div class="step-dot-icon"></div>
+        <div class="info">
+          <div class="left-info">
+            <div class="title">{{ item.title }}</div>
+            <div class="date">{{ formatDate(item.date) }}</div>
+          </div>
+          <div class="right-country">{{ item.country }}</div>
+        </div>
+      </div>
+      <div class="line" v-if="index + 1 !== containerStatusData.length"></div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.container-status {
+  width: 100%;
+  padding: 22px 0 22px;
+}
+
+.step-data {
+  display: flex;
+  gap: 8px;
+  height: 8px;
+  width: 100%;
+  .step-dot-icon {
+    height: 8px;
+    width: 8px;
+    background-color: var(--color-neutral-1);
+    border-radius: 50%;
+  }
+  .info {
+    flex: 1;
+    display: flex;
+    height: 52px;
+    margin-top: -22px;
+    background-color: var(--color-table-header-bg);
+    border: 1px solid var(--color-border);
+    border-radius: 6px;
+    color: var(--color-neutral-1);
+    .left-info {
+      flex: 1;
+      padding: 8px 10px;
+      border-right: 1px solid var(--color-border);
+      .title {
+        font-size: 14px;
+        font-weight: 700;
+      }
+      .date {
+        margin-top: 4px;
+        font-size: 12px;
+      }
+    }
+    .right-country {
+      padding: 0 24px;
+      line-height: 52px;
+      font-weight: 700;
+    }
+  }
+}
+.line {
+  height: 60px;
+  width: 0;
+  margin-left: 3px;
+  border-left: 1px solid var(--color-neutral-1);
+}
+</style>

+ 1 - 0
src/components/CustomizeColumns/index.ts

@@ -0,0 +1 @@
+export { default } from './src/CustomizeColumns.vue'

+ 762 - 0
src/components/CustomizeColumns/src/CustomizeColumns.vue

@@ -0,0 +1,762 @@
+<script setup lang="ts">
+import { VueDraggable } from 'vue-draggable-plus'
+
+const dialogVisible = ref(false)
+// search筛选的字段
+const searchColumn = ref('')
+// search筛选的options
+const searchOptions: any = ref()
+
+// 右侧箭头消失所需要translateX的值
+const rightArrowHideDistance = ref(0)
+// 控制tab栏的左右切换箭头
+const handleTabArrow = () => {
+  const parentElement: HTMLElement | null = document.querySelector('.left-all-columns')
+  if (!parentElement) return
+
+  // 左侧切换箭头
+  const leftArrow: HTMLElement | null = parentElement.querySelector('.el-tabs__nav-prev')
+  // 右侧切换箭头
+  const rightArrow: HTMLElement | null = parentElement.querySelector('.el-tabs__nav-next')
+  const targetObserverElement = parentElement.querySelector('.el-tabs__nav')
+
+  if (!targetObserverElement || !leftArrow || !rightArrow) return
+
+  // 创建一个函数来获取 translateX
+  const getTranslateX = () => {
+    const style = window.getComputedStyle(targetObserverElement)
+    const matrix = style.transform
+
+    if (matrix !== 'none' && matrix) {
+      // 提取 matrix 中的 translateX 值
+      const values = matrix.match(/matrix\(([^)]+)\)/)?.[1].split(', ')
+      if (!values) return 0
+      const translateX = parseFloat(values[4])
+      return translateX
+    }
+    return 0 // 如果没有 transform 或 translateX,默认返回 0
+  }
+
+  // 检查并更新箭头显示状态
+  const updateArrowVisibility = () => {
+    const translateX = getTranslateX()
+    if (translateX === 0) {
+      leftArrow.style.display = 'none'
+    } else {
+      leftArrow.style.display = 'inline-block'
+    }
+
+    if (translateX === rightArrowHideDistance.value) {
+      rightArrow.style.display = 'none'
+    } else {
+      rightArrow.style.display = 'inline-block'
+    }
+  }
+
+  // 监听 transitionend 事件,等待动画结束后再获取 translateX 值
+  targetObserverElement.addEventListener('transitionend', (event: any) => {
+    if (event.propertyName === 'transform') {
+      // 只有 transform 动画结束时才触发
+      updateArrowVisibility()
+    }
+  })
+
+  // 初次运行时手动检查一次
+  updateArrowVisibility()
+}
+
+// 筛选选中时滚动到对应的元素
+const handleDocumentClick = (event: any) => {
+  if (!scrollTargetElement.value.contains(event.target)) {
+    scrollTargetElement.value.className = scrollTargetElement.value.className.replace(
+      'search-select-item',
+      ''
+    )
+    scrollTargetElement.value = null
+    document.removeEventListener('click', handleDocumentClick)
+  }
+}
+const scrollTargetElement = ref()
+const scrollToItem = (itemId: string) => {
+  if (activeName.value !== 'All') {
+    activeName.value = 'All'
+  }
+  setTimeout(() => {
+    // 重置
+    if (scrollTargetElement.value) {
+      scrollTargetElement.value.className = scrollTargetElement.value.className.replace(
+        'search-select-item',
+        ''
+      )
+    }
+    // 获取目标元素
+    scrollTargetElement.value = document.querySelector(`[data-field='${itemId}']`)
+    if (scrollTargetElement.value) {
+      // 使用 scrollIntoView 滚动到该元素
+      scrollTargetElement.value.scrollIntoView({ behavior: 'smooth', block: 'center' })
+      scrollTargetElement.value.className += ' search-select-item'
+      // 或者使用自定义滚动
+      // const container = this.$refs.dataContainer
+      // container.scrollTop = targetElement.offsetTop - container.offsetTop
+
+      document.addEventListener('click', handleDocumentClick)
+    }
+  }, 100)
+}
+
+// 系统首次加载时,会有引导操作
+let firstLoad = localStorage.getItem('firstLoadCustomizeColumns')
+const step1 = ref()
+const open1 = ref(false)
+const step2 = ref()
+const open2 = ref(false)
+const handleCloseTour = (stepStr: string) => {
+  stepStr === 'step1' ? (open1.value = false) : (open2.value = false)
+  localStorage.setItem('firstLoadCustomizeColumns', 'true')
+  // firstLoad = 'true'
+}
+
+// 左侧选中的tab
+const activeName = ref()
+// 分组列
+const groupColumns: any = ref([])
+// 所有数据
+const allDataCopy: any = ref()
+
+const loading = ref(false)
+// 获取数据
+const getData = async (reset?: string) => {
+  loading.value = true
+  let paramsData: any = { ...params.value.getData }
+  if (reset === 'yes') {
+    paramsData.reset = 'yes'
+  }
+  await $api.getTableSettingColumns(paramsData).then((res: any) => {
+    if (res.code === 200) {
+      // allDataCopy就是所有的数据
+      allDataCopy.value = res.data.GroupColumnsAll
+      groupColumns.value = res.data.GroupColumnsLeft
+      activeName.value = allDataCopy.value?.[0]?.name
+      searchOptions.value = res.data.GroupColumnsLeft?.[0]?.children
+      // 右侧选中的数据
+      selectColumns.value = res.data.GroupColumnsRight
+      nextTick(() => {
+        handleTabArrow()
+      })
+    }
+  })
+  loading.value = false
+}
+
+const params = ref()
+// rightDistance是右侧箭头消失所需要translateX的值
+const openDialog = async (paramsData: Object, rightDistance: number) => {
+  params.value = paramsData
+  dialogVisible.value = true
+  await getData()
+  rightArrowHideDistance.value = rightDistance
+  nextTick(() => {
+    if (!firstLoad) {
+      open1.value = true
+      open2.value = true
+    }
+  })
+}
+
+const selectColumns: any = ref([])
+
+// 左侧Icon的显隐
+const hoverAllIcon = ref('')
+// 右侧Icon的显隐
+const hoverSelectIcon = ref('')
+
+const handleAddSelect = (item: any) => {
+  groupColumns.value.forEach((groupItem: any) => {
+    groupItem.children.forEach((child: any, index: number) => {
+      if (child.field === item.field) {
+        groupItem.children.splice(index, 1)
+      }
+    })
+  })
+  selectColumns.value.push(item)
+}
+
+// 从左侧拖拽到右侧时,删除其他分组中相同的数据
+const handleLeftRemove = (e: any) => {
+  if (e.to === e.from) return
+  const curItem = e.data
+  groupColumns.value.forEach((groupItem: any) => {
+    groupItem.children.forEach((child: any, index: number) => {
+      if (child.field === curItem.field) {
+        groupItem.children.splice(index, 1)
+      }
+    })
+  })
+}
+
+// 从右侧拖拽到左侧时,左侧根据分组添加数据
+const handleRightRemove = (e: any) => {
+  if (e.to === e.from) return
+  const curItem = e.data
+  // 获取当前移动项移入到了那一组
+  const curGroup = groupColumns.value.find((item: any) => {
+    return item.name == activeName.value
+  })
+  // 获取当前项应该对应哪一组
+  const originalGroup = allDataCopy.value.find((item: any) => {
+    if (item.name === 'All') {
+      return false
+    }
+    const index = item.children.findIndex((child: any) => {
+      return child.field === curItem.field
+    })
+    return index !== -1
+  })
+
+  if (curGroup.name !== originalGroup.name && curGroup.name !== 'All') {
+    // 从当前分组中删除移入的数据
+    curGroup.children.forEach((item: any, index: number) => {
+      item.field === curItem.field && curGroup.children.splice(index, 1)
+    })
+    // 在对应分组中添加移入的数据
+    groupColumns.value.forEach((item: any) => {
+      item.name === originalGroup.name && item.children.push(curItem)
+    })
+    // 添加到All分组里
+    groupColumns.value[0].children.push(curItem)
+  } else if (curGroup.name === 'All') {
+    // 在对应分组中添加移入的数据
+    groupColumns.value.forEach((item: any) => {
+      item.name === originalGroup.name && item.children.push(curItem)
+    })
+  } else if (curGroup.name === originalGroup.name) {
+    groupColumns.value[0].children.push(curItem)
+  }
+}
+// 点击右侧的减号删除选中的列,并添加到左侧
+const handleDeleteSelect = (curItem: any) => {
+  selectColumns.value.forEach((item: any, index: number) => {
+    if (item.field === curItem.field) {
+      selectColumns.value.splice(index, 1)
+    }
+  })
+  // 获取当前项应该对应哪一组
+  const originalGroup = allDataCopy.value.find((item: any) => {
+    if (item.name === 'All') {
+      return false
+    }
+    const index = item.children.findIndex((child: any) => {
+      return child.field === curItem.field
+    })
+    return index !== -1
+  })
+  // 在对应分组中添加移入的数据
+  groupColumns.value.forEach((item: any) => {
+    item.name === originalGroup.name && item.children.push(curItem)
+  })
+  // 添加到All分组里
+  groupColumns.value[0].children.push(curItem)
+}
+
+const handleMoveUpSelect = (item: any) => {
+  const index = selectColumns.value.findIndex((i: any) => i.field === item.field)
+  if (index === 0) return
+  const temp = selectColumns.value[index]
+  selectColumns.value[index] = selectColumns.value[index - 1]
+  selectColumns.value[index - 1] = temp
+}
+const handleMoveDownSelect = (item: any) => {
+  const index = selectColumns.value.findIndex((i: any) => i.field === item.field)
+  if (index === selectColumns.value.length - 1) return
+  const temp = selectColumns.value[index]
+  selectColumns.value[index] = selectColumns.value[index + 1]
+  selectColumns.value[index + 1] = temp
+}
+
+const emits = defineEmits<{
+  customize: []
+  reset: []
+}>()
+const handleReset = () => {
+  getData('yes')
+}
+const handleApply = () => {
+  const columnsList = selectColumns.value.map((item: any) => {
+    return item.ids
+  })
+  $api
+    .saveTableSettingColumns({
+      ...params.value.saveData,
+      ids: columnsList
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        // ElMessage.success('Save successfully')
+        emits('customize')
+        dialogVisible.value = false
+      }
+    })
+}
+
+const clearData = () => {
+  open1.value = false
+  open2.value = false
+  activeName.value = ''
+  groupColumns.value = []
+  selectColumns.value = []
+  searchColumn.value = ''
+}
+
+defineExpose({
+  openDialog
+})
+</script>
+
+<template>
+  <el-dialog
+    class="customize-columns"
+    v-model="dialogVisible"
+    :width="1000"
+    title="Customize Columns"
+    @close="clearData"
+  >
+    <div class="search-header">
+      <div class="search-input" ref="searchRef">
+        <el-select
+          v-model="searchColumn"
+          @change="scrollToItem"
+          filterable
+          placeholder="Search columns you preffered"
+        >
+          <template #prefix>
+            <span class="iconfont_icon">
+              <svg class="iconfont" aria-hidden="true">
+                <use xlink:href="#icon-icon_search_b"></use>
+              </svg>
+            </span>
+          </template>
+          <el-option
+            v-for="item in searchOptions"
+            :key="item.field"
+            :label="item.label"
+            :value="item.field"
+          />
+        </el-select>
+      </div>
+      <div class="tips">
+        <span style="font-size: 16px">* </span>
+        <span
+          >Drag item over to this selection or click "add" icon to show the column on your booking
+          list</span
+        >
+      </div>
+    </div>
+    <div class="draggable-list">
+      <div class="left-all-columns" v-vloading="loading">
+        <div class="tabs">
+          <el-tabs v-model="activeName">
+            <el-tab-pane
+              v-for="groupItem in groupColumns"
+              :key="groupItem.name"
+              :label="groupItem.name"
+              :name="groupItem.name"
+            >
+              <VueDraggable
+                v-model="groupItem.children"
+                class="column-list"
+                :sort="false"
+                ghost-class="ghost-column"
+                :forceFallback="true"
+                fallbackClass="fallback-class"
+                group="customizeColumns"
+                item-key="field"
+                @end="handleLeftRemove"
+              >
+                <template v-for="(item, index) in groupItem.children" :key="item.field">
+                  <div
+                    :data-field="item.field"
+                    class="column-item"
+                    @mouseenter="hoverAllIcon = item.field"
+                    @mouseleave="hoverAllIcon = ''"
+                  >
+                    <span class="font_family icon-icon_dragsort__b draggable-icon"></span>
+                    <span class="title">{{ item.label }}</span>
+                    <span
+                      ref="step1"
+                      v-if="hoverAllIcon === item.field || (index === 0 && !firstLoad)"
+                      class="font_family icon-icon_add_b move-icon"
+                      @click="handleAddSelect(item)"
+                    ></span>
+                  </div>
+                </template>
+              </VueDraggable>
+            </el-tab-pane>
+          </el-tabs>
+        </div>
+      </div>
+      <div class="right-select-columns">
+        <div class="title">Selected columns on your booking list</div>
+        <VueDraggable
+          v-vloading="loading"
+          v-model="selectColumns"
+          class="column-list"
+          ghost-class="ghost-column"
+          :forceFallback="true"
+          fallback-class="fallback-class"
+          group="customizeColumns"
+          item-key="field"
+          @end="handleRightRemove"
+        >
+          <template v-for="(item, index) in selectColumns" :key="item.field">
+            <div
+              class="column-item"
+              @mouseenter="hoverSelectIcon = item.field"
+              @mouseleave="hoverSelectIcon = ''"
+            >
+              <span
+                class="font_family icon-icon_dragsort__b draggable-icon"
+                style="font-size: 16px"
+              ></span>
+              <span class="title">{{ item.label }}</span>
+              <span
+                v-if="hoverSelectIcon === item.field || (index === 0 && !firstLoad)"
+                class="font_family icon-icon_moveup_b move-icon"
+                @click="handleMoveUpSelect(item)"
+              ></span>
+              <span
+                v-if="hoverSelectIcon === item.field || (index === 0 && !firstLoad)"
+                class="font_family icon-icon_movedown_b move-icon"
+                @click="handleMoveDownSelect(item)"
+              ></span>
+              <span
+                ref="step2"
+                v-if="hoverSelectIcon === item.field || (index === 0 && !firstLoad)"
+                class="font_family icon-icon_reduce_b move-icon"
+                @click="handleDeleteSelect(item)"
+              ></span>
+            </div>
+          </template>
+        </VueDraggable>
+      </div>
+    </div>
+    <template #footer>
+      <el-button type="default" @click="dialogVisible = false">Cancel</el-button>
+      <el-button type="default" @click="handleReset">Reset to default</el-button>
+      <el-button class="el-button--dark" @click="handleApply"> Apply </el-button>
+    </template>
+    <el-tour
+      :target-area-clickable="false"
+      class="step1-tour"
+      v-model="open1"
+      type="primary"
+      :mask="false"
+      v-if="step1?.[0]"
+    >
+      <el-tour-step :show-close="false" :target="step1?.[0]">
+        <template #default>
+          <div class="description">
+            <span>Drag</span> items to the right group or click the "<span>Add</span>" icon to add
+            columns to the shipment list.
+          </div>
+          <div class="got-it-text" @click="handleCloseTour('step1')">Got it</div>
+        </template>
+      </el-tour-step>
+    </el-tour>
+    <el-tour
+      :target-area-clickable="false"
+      class="step2-tour"
+      v-model="open2"
+      type="primary"
+      :mask="false"
+      v-if="step2?.[0]"
+    >
+      <el-tour-step :show-close="false" :target="step2?.[0]">
+        <template #default>
+          <div class="description">
+            <span>Drag</span> items to the left group or click the "<span>Remove</span>" icon to
+            delete columns from the shipment list.
+          </div>
+          <div class="description">
+            <span>Drag</span> items up or down to reorder the shipment list, or use the "<span
+              >Move up</span
+            >" and "<span>Move down</span>" icons.
+          </div>
+          <div class="got-it-text" @click="handleCloseTour('step2')">Got it</div>
+        </template>
+      </el-tour-step>
+    </el-tour>
+  </el-dialog>
+</template>
+
+<style lang="scss">
+.customize-columns {
+  .search-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    gap: 8px;
+    padding: 10px 0;
+
+    .search-input {
+      width: 50%;
+      padding-right: 16px;
+    }
+
+    .tips {
+      display: flex;
+      align-items: flex-start;
+      gap: 3px;
+      width: 50%;
+      padding-left: 5px;
+      vertical-align: middle;
+
+      span {
+        font-size: 12px;
+        color: var(--color-neutral-2);
+      }
+    }
+  }
+
+  .draggable-list {
+    display: flex;
+    user-select: none;
+    gap: 8px;
+  }
+}
+
+.right-select-columns,
+.left-all-columns {
+  width: 50%;
+
+  .column-list {
+    height: 400px;
+    overflow: auto;
+
+    .column-item {
+      display: flex;
+      align-items: center;
+      height: 40px;
+      margin-bottom: 5px;
+      padding-left: 12px;
+      border: 1px solid var(--color-border);
+      border-radius: 6px;
+
+      &:hover {
+        background-color: #fff1e5;
+        box-shadow: 4px 4px 32px 0px rgba(0, 0, 0, 0.1);
+      }
+
+      & > .title {
+        flex: 1;
+      }
+
+      span.draggable-icon {
+        margin-right: 12px;
+        color: var(--color-neutral-3);
+      }
+
+      .font_family {
+        font-size: 16px;
+        cursor: pointer;
+        margin-right: 16px;
+      }
+
+      .move-icon {
+        &:hover {
+          color: var(--color-theme);
+        }
+      }
+    }
+  }
+
+  .ghost-column {
+    opacity: 0;
+    cursor: move !important;
+  }
+
+  .fallback-class {
+    opacity: 1 !important;
+    background-color: #fff1e5 !important;
+    cursor: move !important;
+  }
+}
+
+.left-all-columns {
+  border: 1px solid var(--color-border);
+  border-radius: 12px;
+
+  .tabs {
+    position: relative;
+    height: 100%;
+
+    .el-tabs {
+      .el-tabs__header {
+        margin-bottom: 0px;
+        border-bottom: 1px solid #ebeef5;
+      }
+
+      .el-tabs__item {
+        padding: 10px;
+      }
+    }
+  }
+
+  .column-list {
+    padding: 8px;
+    padding-bottom: 0px;
+  }
+
+  .search-select-item {
+    border: 1px solid var(--color-theme) !important;
+    box-shadow: 2px 2px 12px 0px rgba(237, 109, 0, 0.2);
+
+    .title {
+      color: var(--color-theme) !important;
+    }
+  }
+}
+
+.right-select-columns {
+  background-color: #fffbf7;
+  padding-top: 0;
+  border: 1px dashed var(--color-border);
+  border-radius: 12px;
+
+  & > .title {
+    height: 40px;
+    padding: 8px;
+    line-height: 24px;
+    font-size: 16px;
+    font-weight: 700;
+  }
+
+  .column-list {
+    padding: 8px;
+    padding-bottom: 0px;
+  }
+
+  .column-item {
+    background-color: #fff;
+  }
+}
+</style>
+<style lang="scss">
+.left-all-columns {
+  .el-tabs__nav-prev,
+  .el-tabs__nav-next {
+    height: 40px;
+    width: 40px;
+  }
+
+  .el-tabs__item {
+    color: var(--color-neutral-1);
+    font-weight: 400;
+    font-size: 14px;
+  }
+
+  .el-tabs__item.is-active,
+  .el-tabs__item:hover {
+    font-weight: 700;
+    font-size: 14px;
+    color: var(--color-neutral-1);
+  }
+
+  .el-tabs__nav-prev {
+    border-right: 1px solid var(--color-border);
+    box-shadow: 1px 0px 10px rgba(0, 0, 0, 0.2);
+    /* 左侧阴影 */
+  }
+
+  .el-tabs__nav-next {
+    border-left: 1px solid var(--color-border);
+    box-shadow: -1px 0px 10px rgba(0, 0, 0, 0.2);
+    /* 左侧阴影 */
+  }
+
+  .el-tabs__nav-wrap {
+    padding: 0 40px;
+  }
+
+  .el-tabs__item.is-active,
+  .el-tabs__item:hover {
+    color: var(--color-theme);
+  }
+
+  .el-tabs__active-bar {
+    background-color: var(--color-theme);
+  }
+}
+
+.search-header {
+  & > .search-input {
+    .el-select {
+      width: 100%;
+
+      .el-select__wrapper {
+        border-radius: 20px;
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+.step1-tour {
+  .el-tour__content {
+    width: 240px;
+    height: 124px;
+    background-color: var(--color-theme);
+    z-index: 9999 !important;
+  }
+
+  .el-tour__arrow {
+    background-color: var(--color-theme);
+  }
+
+  .el-tour__footer {
+    display: none;
+  }
+}
+
+.step2-tour {
+  .el-tour__content {
+    width: 240px;
+    height: 200px;
+    background-color: var(--color-theme);
+    z-index: 9999 !important;
+  }
+
+  .el-tour__arrow {
+    background-color: var(--color-theme);
+  }
+
+  .el-tour__footer {
+    display: none;
+  }
+}
+
+.step1-tour,
+.step2-tour {
+  .el-tour__header {
+    display: none;
+  }
+
+  .description {
+    margin-bottom: 16px;
+    color: white;
+    line-height: 22px;
+
+    span {
+      color: white;
+      font-weight: 600;
+    }
+  }
+
+  .got-it-text {
+    float: right;
+    color: white;
+    font-weight: 700;
+    cursor: pointer;
+  }
+}
+</style>

+ 1 - 0
src/components/DateRange/index.ts

@@ -0,0 +1 @@
+export { default } from './src/DateRange.vue'

+ 295 - 0
src/components/DateRange/src/DateRange.vue

@@ -0,0 +1,295 @@
+<script setup lang="ts">
+import emitter from '@/utils/bus'
+import { ref, computed, onMounted, onBeforeMount } from 'vue'
+import IconDropDown from '@/components/IconDropDown'
+import CalendarDate from './components/CalendarDate.vue'
+
+onMounted(() => {
+  emitter.on('clearTag', (tag: any) => {
+    if (tag.includes('ETD')) {
+      clearDateStart()
+    } else if (tag.includes('ETA')) {
+      clearDateEnd()
+    } else {
+      clearDateCreation()
+    }
+  })
+  emitter.on('clearDaterangeObj', () => {
+    clearDaterangeObj()
+  })
+})
+
+onBeforeMount(() => {
+  emitter.off('clearTag')
+  emitter.off('clearDaterangeObj')
+})
+
+const Date_visible = ref(false)
+const DateType = ref()
+const DateTypeoptions = ref([
+  {
+    value: 'Creation Time',
+    label: 'Creation Time'
+  }
+])
+const AddDateType = ref()
+AddDateType.value = []
+const AddType = () => {
+  AddDateType.value.push({
+    value: '',
+    number: ''
+  })
+}
+const deleteType = (i: any) => {
+  AddDateType.value.splice(i, 1)
+  DateType.value = ''
+}
+let daterangeObj: any = {}
+const DateStart = ref()
+const DateEnd = ref()
+const DateCreation = ref()
+const daterangedata = ref()
+daterangedata.value = []
+const DateRangeChange = (val: any) => {
+  daterangeObj[val.title] = val.data[0] + ' To ' + val.data[1]
+}
+const emit = defineEmits(['DateRangeSearch', 'clearDaterangeTags'])
+const DateRangeSearch = () => {
+  emit('DateRangeSearch', daterangeObj)
+  Date_visible.value = false
+}
+const CalendarTitle = computed(() => {
+  if (DateType.value == 'undefined') {
+    return 'Date Range'
+  } else {
+    return DateType.value
+  }
+})
+// 清除
+const clearrest = () => {
+  emit('clearDaterangeTags')
+  clearDateStart()
+  clearDateEnd()
+  clearDateCreation()
+}
+// 清除EDT
+const clearDateStart = () => {
+  DateStart.value = []
+  delete daterangeObj['ETD']
+}
+// 清除EDA
+const clearDateEnd = () => {
+  DateEnd.value = []
+  delete daterangeObj['ETA']
+}
+// 清除Creation Time
+const clearDateCreation = () => {
+  DateCreation.value = []
+  AddDateType.value = []
+  DateType.value = ''
+  delete daterangeObj['Creation Time']
+}
+// 清除 daterangeObj
+const clearDaterangeObj = () => {
+  daterangeObj = {}
+}
+</script>
+<template>
+  <div class="select">
+    <el-popover trigger="click" :width="400" :visible="Date_visible">
+      <template #reference>
+        <div class="Date_Range" @click="Date_visible = !Date_visible">
+          <div class="select_title">Date Range</div>
+          <span class="iconfont_icon">
+            <svg class="iconfont" aria-hidden="true">
+              <use xlink:href="#icon-icon_dropdown_b"></use>
+            </svg>
+          </span>
+        </div>
+      </template>
+      <div>
+        <div class="title">Date Range</div>
+        <div class="ETD">
+          <CalendarDate
+            CalendarTitle="ETD"
+            :Date="DateStart"
+            @DateRangeChange="DateRangeChange"
+          ></CalendarDate>
+        </div>
+        <div class="ETA">
+          <CalendarDate
+            CalendarTitle="ETA"
+            :Date="DateEnd"
+            @DateRangeChange="DateRangeChange"
+          ></CalendarDate>
+        </div>
+        <div class="AddType" v-for="(item, index) in AddDateType" :key="item">
+          <div>
+            <div class="ETD_title Date_Title">
+              <div>Date Type</div>
+              <span class="iconfont_icon" @click="deleteType(index)">
+                <svg class="iconfont icon_delete" aria-hidden="true">
+                  <use xlink:href="#icon-icon_delete_b"></use>
+                </svg>
+              </span>
+            </div>
+            <el-select
+              :suffix-icon="IconDropDown"
+              placeholder="Please Select Date Type"
+              v-model="DateType"
+            >
+              <el-option
+                v-for="item in DateTypeoptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              >
+              </el-option>
+            </el-select>
+          </div>
+          <div style="margin-top: 16px">
+            <CalendarDate
+              :CalendarTitle="CalendarTitle"
+              CalendarWidth="352px"
+              :Date="DateCreation"
+              @DateRangeChange="DateRangeChange"
+            ></CalendarDate>
+          </div>
+        </div>
+        <div class="MoreType" @click="AddType" v-if="AddDateType.length != DateTypeoptions.length">
+          + More Date Type
+        </div>
+        <div class="daterange_bottom">
+          <div><el-button type="default" @click="clearrest" class="Clear">Reset</el-button></div>
+          <div>
+            <el-button class="search el-button--dark" @click="DateRangeSearch">Search</el-button>
+          </div>
+        </div>
+      </div>
+    </el-popover>
+  </div>
+</template>
+<style lang="scss" scoped>
+.iconfont_icon {
+  margin-right: 8px;
+}
+.icon_delete {
+  fill: var(--color-danger);
+}
+.select {
+  width: 186px;
+  margin-left: 8px;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  border: 1px solid var(--color-border);
+  border-radius: var(--border-radius-6);
+}
+.Date_Range {
+  width: 186px;
+  display: flex;
+  position: relative;
+  align-items: center;
+  justify-content: space-between;
+}
+.select_title {
+  font-size: var(--font-size-3);
+  font-weight: 400;
+  margin-left: 8.53px;
+  color: var(--color-neutral-1);
+}
+.select_icon {
+  width: 16px;
+  margin-right: 10.5px;
+}
+.select:hover {
+  border: 1px solid var(--color-theme);
+}
+.title {
+  font-weight: 700;
+  font-size: var(--font-size-5);
+  background-color: #f6f8fa;
+  height: 48px;
+  display: flex;
+  align-items: center;
+  padding-left: 16px;
+}
+.ETD {
+  margin: 8px 16px;
+}
+.ETA {
+  margin: 16px 16px;
+}
+.ETD_title {
+  font-size: var(--font-size-2);
+  margin-bottom: 4px;
+  color: var(--color-neutral-2);
+}
+.Date_Title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+:deep(.el-dialog__header) {
+  display: none;
+}
+:deep(div.el-dialog) {
+  width: 400px;
+  padding: 0;
+  margin-top: 202px;
+  border: 1px solid var(--color-border);
+}
+:deep(div.el-dialog__body) {
+  padding: 0;
+}
+.MoreType {
+  color: var(--color-accent-2);
+  padding: 0 0 16px 16px;
+}
+:deep(.el-select__wrapper) {
+  border-radius: var(--border-radius-6);
+  height: 40px;
+}
+.AddType {
+  background-color: var(--color-neutral-4);
+  margin: 0 16px 8px 16px;
+  padding: 8px;
+  border-radius: var(--border-radius-6);
+}
+.daterange_bottom {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  height: 48px;
+  border-top: 1px solid var(--color-border);
+  margin-top: 5px;
+  font-weight: 400;
+  font-size: var(--font-size-3);
+}
+.Clear {
+  width: 81px;
+  height: 32px;
+  margin-right: 7.82px;
+}
+.search {
+  width: 86px;
+  height: 32px;
+  margin-right: 16px;
+}
+:deep(.el-date-editor .el-range__icon) {
+  position: absolute;
+  right: 16px;
+}
+@media only screen and (min-width: 1280px) {
+  .Date_Range,
+  .select {
+    width: 224px;
+  }
+}
+@media only screen and (min-width: 1440px) {
+  .Date_Range,
+  .select {
+    width: 336px;
+  }
+}
+</style>

+ 135 - 0
src/components/DateRange/src/components/CalendarDate.vue

@@ -0,0 +1,135 @@
+<script lang="ts" setup>
+import dayjs, { Dayjs } from 'dayjs'
+import { ref, watch } from 'vue'
+
+// type RangeValue = [Dayjs, Dayjs]
+// const ETDDate = ref<RangeValue>()
+const props = defineProps({
+  CalendarWidth: {
+    type: String,
+    default: '368px'
+  },
+  CalendarTitle: {
+    type: String
+  },
+  Date: {
+    type: Array
+  }
+})
+const ETDDate = ref(props.Date)
+watch(
+  () => props.Date,
+  (current) => {
+    ETDDate.value = current
+  }
+)
+const emit = defineEmits(['DateRangeChange'])
+const open = ref(false)
+const Disabled = ref([false, false])
+const isShowExtra = ref(true)
+
+const ChangeToday = (val: any) => {
+  console.log(ETDDate.value)
+  if (val == 'Earliest') {
+    // ETDDate.value = [dayjs(), dayjs()]
+    ETDDate.value[0] = dayjs()
+    open.value = false
+    console.log(ETDDate.value)
+  } else {
+    ETDDate.value[1] = dayjs()
+    open.value = false
+    // ETDDate.value = [dayjs(), dayjs()]
+  }
+}
+const handleCalendarOpen = () => {
+  open.value = !open.value
+}
+const Earliest = () => {
+  Disabled.value = [true, false]
+  ETDDate.value = [dayjs('Oct-05-2009'), dayjs()]
+}
+const Latest = () => {
+  Disabled.value = [false, true]
+}
+const changeRangeData = (value: any) => {
+  if (value != '') {
+    const rangedata = {
+      title: props.CalendarTitle,
+      data: value
+    }
+    emit('DateRangeChange', rangedata)
+  }
+}
+const handlePanelChange = (value: any, mode: any) => {
+  if (mode[0] == 'year' || mode[0] == 'month') {
+    isShowExtra.value = false
+  } else {
+    isShowExtra.value = true
+  }
+}
+</script>
+<template>
+  <div>
+    <div class="ETD_title">{{ props.CalendarTitle }}</div>
+    <a-range-picker
+      separator="To"
+      :showToday="false"
+      :allowClear="false"
+      :style="{ width: props.CalendarWidth }"
+      :open="open"
+      :disabled="Disabled"
+      @change="changeRangeData"
+      :placeholder="['Start Time', 'End Time']"
+      format="MMM-DD-YYYY"
+      valueFormat="MMM-DD-YYYY"
+      @openChange="handleCalendarOpen"
+      @panelChange="handlePanelChange"
+      v-model:value="ETDDate"
+    >
+      <template #suffixIcon>
+        <span class="iconfont_icon">
+          <svg class="iconfont" aria-hidden="true">
+            <use xlink:href="#icon-icon_date_b"></use>
+          </svg>
+        </span>
+      </template>
+      <template #renderExtraFooter v-if="isShowExtra">
+        <div class="flex">
+          <div class="footer_left">
+            <el-button class="el-button--noborder" @click="Earliest">Earliest Time</el-button>
+            <el-button class="el-button--noborder" @click="ChangeToday('Earliest')"
+              >Today</el-button
+            >
+          </div>
+          <div class="footer_left footer_right">
+            <el-button @click="Latest" class="el-button--noborder">Latest Time</el-button>
+            <el-button class="el-button--noborder" @click="ChangeToday('Latest')">Today</el-button>
+          </div>
+        </div>
+      </template>
+    </a-range-picker>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.flex {
+  display: flex;
+  justify-content: space-between;
+}
+.footer_left {
+  display: flex;
+  flex: 50%;
+  padding: 4px 0 4px 8px;
+}
+.footer_right {
+  border-left: 1px solid var(--color-border);
+}
+.el-button--noborder {
+  color: var(--color-theme);
+}
+.ETD_title {
+  font-size: var(--font-size-2);
+  margin-bottom: 4px;
+  color: var(--color-neutral-2);
+}
+</style>

+ 1 - 0
src/components/FliterTags/index.ts

@@ -0,0 +1 @@
+export { default } from './src/FilterTags.vue'

+ 165 - 0
src/components/FliterTags/src/FilterTags.vue

@@ -0,0 +1,165 @@
+<script setup lang="ts">
+import { ref, watch } from 'vue'
+interface ListItem {
+  name: string
+  number: number
+  type: string
+  checked: boolean
+}
+interface Props {
+  TagsListItem: ListItem[]
+}
+const props = withDefaults(defineProps<Props>(), {})
+
+const TagsList = ref(props.TagsListItem)
+const NewTagsList = ref()
+
+watch(
+  () => props.TagsListItem,
+  (current) => {
+    TagsList.value = current
+  }
+)
+
+NewTagsList.value = []
+
+let checkedCount: any[] = []
+const emits = defineEmits(['changeTag'])
+const checkedBox = (i: any, name: any, checked: any) => {
+  if (name == 'All') {
+    checkedCount = []
+    TagsList.value.forEach((item: any) => {
+      item.checked = false
+    })
+    TagsList.value[0].checked = true
+  } else if (!checked) {
+    TagsList.value[0].checked = false
+    TagsList.value[i].checked = !TagsList.value[i].checked
+    checkedCount.push(name)
+    const map = new Map()
+    checkedCount.forEach((item) => map.set(item, true))
+    checkedCount = [...map.keys()]
+  } else {
+    checkedCount.pop()
+    TagsList.value[0].checked = false
+    TagsList.value[i].checked = !TagsList.value[i].checked
+  }
+  if (checkedCount.length === TagsList.value.length - 1 || checkedCount.length == 0) {
+    checkedCount = []
+    TagsList.value.forEach((item: any) => {
+      item.checked = false
+    })
+    TagsList.value[0].checked = true
+  }
+  if (checkedCount.length == 0) {
+    NewTagsList.value = ['All']
+  } else {
+    NewTagsList.value = checkedCount
+  }
+  emits('changeTag', NewTagsList.value)
+}
+</script>
+
+<template>
+  <div class="body">
+    <div class="TagsBox">
+      <div
+        class="list"
+        v-for="(item, index) of TagsList"
+        :key="index"
+        :class="[item.checked ? 'checked' : '']"
+        @click="checkedBox(index, item.name, item.checked)"
+      >
+        {{ item.name }}
+        <div
+          :class="[
+            'v-tag',
+            item.type && 'v-tag__' + item.type,
+            item.checked ? 'checked_color' : ''
+          ]"
+        >
+          {{ item.number }}
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.body {
+  margin-top: 8.73px;
+}
+.TagsBox {
+  display: flex;
+  flex-wrap: wrap;
+}
+.list {
+  margin-right: 16px;
+  min-width: 93px;
+  padding: 5.42px 16px;
+  color: var(--color-neutral-2);
+  font-size: var(--font-size-3);
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: var(--border-radius-12);
+}
+.v-tag {
+  min-width: 36px;
+  font-size: var(--font-size-2);
+  margin-left: 6px;
+  border-radius: 6px;
+  padding: 3px;
+  text-align: center;
+}
+.v-tag__all {
+  font-weight: 400;
+  background-color: var(--color-tag-all-bg);
+  color: var(--color-tag-all);
+}
+.v-tag__created {
+  font-weight: 400;
+  background-color: var(--color-tag-created-bg);
+  color: var(--color-tag-created);
+}
+.v-tag__confirmed {
+  font-weight: 400;
+  background-color: var(--color-tag-confirmed-bg);
+  color: var(--color-tag-confirmed);
+}
+.v-tag__cancelled {
+  font-weight: 400;
+  background-color: var(--color-tag-cancelled-bg);
+  color: var(--color-tag-cancelled);
+}
+.v-tag__departure {
+  font-weight: 400;
+  background-color: var(--color-tag-departure-bg);
+  color: var(--color-tag-departure);
+}
+.v-tag__cargo_received {
+  font-weight: 400;
+  background-color: var(--color-tag-cargo-received-bg);
+  color: var(--color-tag-cargo-received);
+}
+.v-tag__arrived {
+  font-weight: 400;
+  background-color: var(--color-tag-arrived-bg);
+  color: var(--color-tag-arrived);
+}
+.v-tag__completed {
+  font-weight: 400;
+  background-color: var(--color-tag-completed-bg);
+  color: var(--color-tag-completed);
+}
+.checked {
+  color: var(--color-tag-all);
+  font-weight: 700;
+  background: var(--color-tag-checked-all);
+}
+.checked_color {
+  background-color: var(--color-tag-all-bg);
+  color: var(--color-tag-all);
+}
+</style>

+ 1 - 0
src/components/Icon/index.ts

@@ -0,0 +1 @@
+export { default as Icon } from './src/IconView.vue'

+ 63 - 0
src/components/Icon/src/IconView.vue

@@ -0,0 +1,63 @@
+<template>
+  <div :style="containerStyle" v-if="svgContent" v-html="svgContent"></div>
+</template>
+
+<script setup>
+import { ref, onMounted, watch } from 'vue'
+
+const props = defineProps({
+  name: {
+    type: String,
+    required: true
+  },
+  size: {
+    type: String,
+    default: '100'
+  },
+  color: {
+    type: String,
+    default: 'currentColor'
+  }
+})
+
+const svgContent = ref('')
+
+// 设置容器的样式
+const containerStyle = computed(() => ({
+  width: props.size,
+  height: props.size
+}))
+
+// 监听name属性变化
+watch(() => props.name, fetchSvg)
+
+// 加载SVG文件并添加样式
+async function fetchSvg() {
+  try {
+    const response = await fetch(
+      new URL(`../../src/icons/${props.name}.svg`, 'http://localhost').href
+    )
+    let svg = await response.text()
+
+    // 使用正则表达式替换fill属性
+    svg = svg.replace(/fill="[^"]*"/g, `fill="${props.color}"`)
+
+    // 将大小属性直接应用到svg标签
+    svg = svg.replace(/<svg/, `<svg width="${props.size}" height="${props.size}"`)
+
+    svgContent.value = svg
+  } catch (error) {
+    console.error(`Error fetching SVG: ${error.message}`)
+  }
+}
+
+// 在组件挂载时加载SVG
+onMounted(fetchSvg)
+</script>
+
+<style scoped>
+div {
+  display: inline-block;
+  vertical-align: middle;
+}
+</style>

+ 1 - 0
src/components/IconDropDown/index.ts

@@ -0,0 +1 @@
+export { default } from './src/IconDropDown.vue'

+ 18 - 0
src/components/IconDropDown/src/IconDropDown.vue

@@ -0,0 +1,18 @@
+<template>
+  <span class="iconfont_icon">
+    <svg class="iconfont iconfont_select" aria-hidden="true">
+      <use xlink:href="#icon-icon_dropdown_b"></use>
+    </svg>
+  </span>
+</template>
+
+<style lang="scss" scoped>
+.iconfont_icon {
+  margin-right: 8px;
+}
+.iconfont_select {
+  width: 17px;
+  height: 17px;
+  fill: var(--color-btn-default-dark-bg);
+}
+</style>

+ 1 - 0
src/components/MoreFilters/index.ts

@@ -0,0 +1 @@
+export { default } from './src/MoreFilters.vue'

+ 816 - 0
src/components/MoreFilters/src/MoreFilters.vue

@@ -0,0 +1,816 @@
+<script setup lang="ts">
+import emitter from '@/utils/bus'
+import AutoSelect from '@/components/AutoSelect'
+import SelectAutoSelect from '@/components/SelectAutoSelect'
+import SelectTableSelect from '@/components/SelectTableSelect'
+import { ref, onMounted, onBeforeMount } from 'vue'
+import SelectTable from '@/components/SelectTable/src/SelectTable.vue'
+
+onMounted(() => {
+  emitter.on('clearTag', (tag: any) => {
+    console.log(tag)
+    if (tag.includes('shippername')) {
+      clearname(InputForm.value, 'parties', 'shippername')
+    } else if (tag.includes('consigneename')) {
+      clearname(InputForm.value, 'parties', 'consigneename')
+    } else if (tag.includes('Incoterms')) {
+      clearname(InputForm.value, 'General', 'Incoterms')
+    } else if (tag.includes('Service')) {
+      clearname(InputForm.value, 'General', 'Service')
+    } else if (tag.includes('vessel')) {
+      clearname(InputForm.value, 'transportation', 'vessel')
+    } else if (tag.includes('voyage')) {
+      clearname(InputForm.value, 'transportation', 'voyage')
+    } else if (tag.includes('origin')) {
+      clearname(InputForm.value, 'palces', 'origin')
+    } else if (tag.includes('destination')) {
+      clearname(InputForm.value, 'palces', 'destination')
+    } else if (tag.includes('Origin Agent')) {
+      AddDateType.value = AddDateType.value.filter((item: any) => item.partyType !== 'Origin Agent')
+      delete MoreFiltersObj['Origin Agent']
+      selectedPartyTypeoptions.value = selectedPartyTypeoptions.value.filter(
+        (item: any) => item !== 'Origin Agent'
+      )
+    } else if (tag.includes('Destination Agent')) {
+      AddDateType.value = AddDateType.value.filter(
+        (item: any) => item.partyType !== 'Destination Agent'
+      )
+      delete MoreFiltersObj['Destination Agent']
+      selectedPartyTypeoptions.value = selectedPartyTypeoptions.value.filter(
+        (item: any) => item !== 'Destination Agent'
+      )
+    } else if (tag.includes('Sales')) {
+      AddDateType.value = AddDateType.value.filter((item: any) => item.partyType !== 'Sales')
+      delete MoreFiltersObj['Sales']
+      selectedPartyTypeoptions.value = selectedPartyTypeoptions.value.filter(
+        (item: any) => item !== 'Sales'
+      )
+    } else if (tag.includes('Place of Receipt')) {
+      AddDatePlaceType.value = AddDatePlaceType.value.filter(
+        (item: any) => item.placesType !== 'Place of Receipt'
+      )
+      delete MoreFiltersObj['Place of Receipt']
+      selectedPlacesTypeoptions.value = selectedPlacesTypeoptions.value.filter(
+        (item: any) => item !== 'Place of Receipt'
+      )
+    } else if (tag.includes('Port of Loading')) {
+      AddDatePlaceType.value = AddDatePlaceType.value.filter(
+        (item: any) => item.placesType !== 'Port of Loading'
+      )
+      delete MoreFiltersObj['Port of Loading']
+      selectedPlacesTypeoptions.value = selectedPlacesTypeoptions.value.filter(
+        (item: any) => item !== 'Port of Loading'
+      )
+    } else if (tag.includes('Place of delivery')) {
+      AddDatePlaceType.value = AddDatePlaceType.value.filter(
+        (item: any) => item.placesType !== 'Place of delivery'
+      )
+      delete MoreFiltersObj['Place of delivery']
+      selectedPlacesTypeoptions.value = selectedPlacesTypeoptions.value.filter(
+        (item: any) => item !== 'Place of delivery'
+      )
+    }
+  })
+  emitter.on('clearDaterangeObj', () => {
+    clearMoreFiltersObj()
+  })
+})
+
+onBeforeMount(() => {
+  emitter.off('clearTag')
+  emitter.off('clearMoreFiltersObj')
+})
+
+const drawer = ref(false)
+interface TypeItem {
+  partyType: ''
+  partyname: []
+  isshowVerfication: boolean
+}
+interface PlacesTypeItem {
+  placesType: ''
+  placesname: []
+  isshowVerfication: boolean
+}
+const AddDateType = ref<TypeItem[]>([])
+const AddDatePlaceType = ref<PlacesTypeItem[]>([])
+const PartyTypeoptions = ref([
+  {
+    value: 'Origin Agent',
+    label: 'Origin Agent'
+  },
+  {
+    value: 'Destination Agent',
+    label: 'Destination Agent'
+  },
+  {
+    value: 'Sales',
+    label: 'Sales'
+  }
+])
+const PlaceTypeoptions = ref([
+  {
+    value: 'Place of Receipt',
+    label: 'Place of Receipt'
+  },
+  {
+    value: 'Port of Loading',
+    label: 'Port of Loading'
+  },
+  {
+    value: 'Place of delivery',
+    label: 'Place of delivery'
+  }
+])
+
+const partSelectTableSelectRef = ref(null)
+const placeSelectTableSelectRef = ref(null)
+
+const selectedPartyTypeoptions = ref()
+selectedPartyTypeoptions.value = []
+
+const selectedPlacesTypeoptions = ref()
+selectedPlacesTypeoptions.value = []
+
+const selectedPartyTypeIndex = ref()
+selectedPartyTypeIndex.value = []
+
+const selectedPlacesTypeIndex = ref()
+selectedPlacesTypeIndex.value = []
+
+const InputForm = ref({
+  parties: {
+    shippername: [],
+    consigneename: []
+  },
+  transportation: {
+    vessel: [],
+    voyage: []
+  },
+  palces: {
+    origin: [],
+    destination: []
+  },
+  General: {
+    Incoterms: '',
+    Service: ''
+  }
+})
+const props = defineProps({
+  isShipment: Boolean
+})
+
+const AddType = (item: any) => {
+  if (item == 'party') {
+    AddDateType.value.push({
+      partyType: '',
+      partyname: [],
+      isshowVerfication: false
+    })
+  } else if (item == 'place') {
+    AddDatePlaceType.value.push({
+      placesType: '',
+      placesname: [],
+      isshowVerfication: false
+    })
+  }
+}
+const count = ref()
+const countT = ref()
+const countP = ref()
+const countG = ref()
+const PartiesBadge = ref('')
+const GeneralBadge = ref('')
+const TransportationBadge = ref()
+const PlacesBadge = ref()
+count.value = []
+countT.value = []
+countP.value = []
+countG.value = []
+
+const changeAll = (value: any, countTotal: any, BadegTotal: any) => {
+  for (let key in value) {
+    if (value[key] != '') {
+      countTotal.push(value[key])
+    }
+  }
+  if (countTotal.length == 0) {
+    BadegTotal.value = ''
+  } else {
+    BadegTotal.value = countTotal.length
+  }
+}
+// 折叠面板生成badge
+const changeCollapse = (val: any) => {
+  if (val.indexOf('Parties') == -1) {
+    AddDateType.value.forEach((item: any) => {
+      if (item.partyType != '' && item.partyname.length != 0) {
+        count.value.push(item.partyname)
+      }
+    })
+    changeAll(InputForm.value.parties, count.value, PartiesBadge)
+    count.value = []
+  } else {
+    PartiesBadge.value = ''
+  }
+  if (val.indexOf('General') == -1) {
+    changeAll(InputForm.value.General, countG.value, GeneralBadge)
+    countG.value = []
+  } else {
+    GeneralBadge.value = ''
+  }
+  if (val.indexOf('Transportation') == -1) {
+    changeAll(InputForm.value.transportation, countT.value, TransportationBadge)
+    countT.value = []
+  } else {
+    TransportationBadge.value = ''
+  }
+  if (val.indexOf('Places') == -1) {
+    AddDatePlaceType.value.forEach((item: any) => {
+      if (item.partyType != '' && item.partyname.length != 0) {
+        countP.value.push(item.partyname)
+      }
+    })
+    changeAll(InputForm.value.palces, countP.value, PlacesBadge)
+    countP.value = []
+  } else {
+    PlacesBadge.value = ''
+  }
+}
+const verification = ref('')
+const placesVerification = ref('')
+let MoreFiltersObj: any = {}
+// 赋值
+const changeAutoSelect = (Array: any, val: any, value: any, arraykey1: any, arraykey2: any) => {
+  if (value == 'InputForm') {
+    if (Array) {
+      Array[arraykey1][arraykey2] = val.value
+      MoreFiltersObj[arraykey2] = val.value.join()
+    }
+  } else if (value == 'AddDateType') {
+    if (Array.length) {
+      Array.forEach((item: any) => {
+        if (item.partyType == arraykey1) {
+          item.partyname = val.value
+        }
+        MoreFiltersObj[item.partyType] = val.value.join()
+      })
+    }
+  }
+}
+const changeAutoSelectshippername = (val: any) => {
+  changeAutoSelect(InputForm.value, val, 'InputForm', 'parties', 'shippername')
+}
+const changeAutoSelectconsigneename = (val: any) => {
+  changeAutoSelect(InputForm.value, val, 'InputForm', 'parties', 'consigneename')
+}
+const changeAutoSelectvessel = (val: any) => {
+  changeAutoSelect(InputForm.value, val, 'InputForm', 'transportation', 'vessel')
+}
+const changeAutoSelectvoyage = (val: any) => {
+  changeAutoSelect(InputForm.value, val, 'InputForm', 'transportation', 'voyage')
+}
+const check = (row: any, value: any, key1: any, key2: any) => {
+  value[key1][key2] = row
+  MoreFiltersObj[key2] = row
+}
+//选择origin
+const checkorigin = (row: any) => {
+  if (row) {
+    check(row, InputForm.value, 'palces', 'origin')
+  }
+}
+const checkdestination = (row: any) => {
+  if (row) {
+    check(row, InputForm.value, 'palces', 'destination')
+  }
+}
+const delSelect = (i: any, val: any) => {
+  let index = selectedPartyTypeoptions.value.findIndex((item: any) => {
+    return item == val
+  })
+  if (index >= 0) {
+    selectedPartyTypeoptions.value.splice(index, 1)
+  }
+  let j = selectedPartyTypeIndex.value.findIndex((item: any) => {
+    return item == i
+  })
+  if (j >= 0) {
+    for (let i = 0; i < selectedPartyTypeIndex.value.length; i++) {
+      if (selectedPartyTypeIndex.value[i] > j) {
+        selectedPartyTypeIndex.value[i] = selectedPartyTypeIndex.value[i] - 1
+      }
+    }
+    selectedPartyTypeIndex.value.splice(j, 1)
+  }
+}
+const delPlacesSelect = (i: any, val: any) => {
+  let index = selectedPlacesTypeoptions.value.findIndex((item: any) => {
+    return item == val
+  })
+  if (index >= 0) {
+    selectedPlacesTypeoptions.value.splice(index, 1)
+  }
+  let j = selectedPlacesTypeIndex.value.findIndex((item: any) => {
+    return item == i
+  })
+  if (j >= 0) {
+    for (let i = 0; i < selectedPlacesTypeIndex.value.length; i++) {
+      if (selectedPlacesTypeIndex.value[i] > j) {
+        selectedPlacesTypeIndex.value[i] = selectedPlacesTypeIndex.value[i] - 1
+      }
+    }
+    selectedPlacesTypeIndex.value.splice(j, 1)
+  }
+}
+const pushSelectedList = (i: any, val: any) => {
+  let index = selectedPartyTypeoptions.value.findIndex((item: any) => {
+    return item == val
+  })
+  if (index < 0) {
+    if (!selectedPartyTypeIndex.value.includes(i)) {
+      selectedPartyTypeoptions.value.push(val)
+      selectedPartyTypeIndex.value.push(i)
+    } else {
+      let j = selectedPartyTypeIndex.value.findIndex((con: any) => {
+        return con == i
+      })
+      selectedPartyTypeoptions.value.splice(i, 1, val)
+    }
+  }
+}
+
+const pushPlacesSelectedList = (i: any, val: any) => {
+  let index = selectedPlacesTypeoptions.value.findIndex((item: any) => {
+    return item == val
+  })
+  if (index < 0) {
+    if (!selectedPlacesTypeIndex.value.includes(i)) {
+      selectedPlacesTypeoptions.value.push(val)
+      selectedPlacesTypeIndex.value.push(i)
+    } else {
+      let j = selectedPlacesTypeIndex.value.findIndex((con: any) => {
+        return con == i
+      })
+      selectedPlacesTypeoptions.value.splice(i, 1, val)
+    }
+  }
+}
+const changeAutoSelectAddType = (index: any, val: any) => {
+  pushSelectedList(index, val)
+}
+
+const changeAutoSelectPlacesAddType = (index: any, val: any) => {
+  pushPlacesSelectedList(index, val)
+}
+const changeAutoSelectVal = (val: any) => {
+  MoreFiltersObj = { ...MoreFiltersObj, ...val }
+}
+// 点击search
+const emit = defineEmits(['MoreFiltersSearch', 'clearMoreFiltersTags'])
+const SearchMore = () => {
+  // 判断是否有验证样式
+  const input_change = document.getElementsByClassName('input_change')
+  if (AddDateType.value.length) {
+    AddDateType.value.forEach((item: any, index: any) => {
+      if (item.partyType != '' && item.partyname.length == 0) {
+        item.isshowVerfication = true
+        verification.value = 'Please input Party Details'
+        input_change[index].classList.add('AlertInput')
+      } else {
+        item.isshowVerfication = false
+        input_change[index].classList.remove('AlertInput')
+      }
+    })
+    const AlertInput = document.getElementsByClassName('AlertInput')
+    if (AlertInput.length == 0) {
+      // 传数据给父组件
+      emit('MoreFiltersSearch', MoreFiltersObj)
+      drawer.value = false
+    }
+  } else {
+    // 传数据给父组件
+    emit('MoreFiltersSearch', MoreFiltersObj)
+    drawer.value = false
+  }
+}
+// 清除
+const clearrest = () => {
+  emit('clearMoreFiltersTags')
+  InputForm.value = {
+    parties: {
+      shippername: [],
+      consigneename: []
+    },
+    transportation: {
+      vessel: [],
+      voyage: []
+    },
+    palces: {
+      origin: [],
+      destination: []
+    },
+    General: {
+      Incoterms: 'Please Select Date Range',
+      Service: 'Please Select Date Range'
+    }
+  }
+  AddDateType.value = []
+  AddDatePlaceType.value = []
+  PartiesBadge.value = ''
+  GeneralBadge.value = ''
+  TransportationBadge.value = ''
+  PlacesBadge.value = ''
+  MoreFiltersObj = {}
+  selectedPartyTypeoptions.value = []
+  selectedPlacesTypeoptions.value = []
+  IncotermsList.value.forEach((item) => {
+    item.checked = false
+  })
+  SeiviceList.value.forEach((item) => {
+    item.checked = false
+  })
+  IncotermsCheckAll.value = false
+  ServiceCheckAll.value = false
+}
+// 清除name
+const clearname = (val: any, key1: any, key2: any) => {
+  if (key2 == 'partyType' || key2 == 'partyname') {
+    val[key1][key2] = ''
+  } else if (key2 == 'Incoterms') {
+    val[key1][key2] = 'Please Select Date Range'
+  } else {
+    val[key1][key2] = []
+  }
+  delete MoreFiltersObj[key2]
+}
+// 清除 MoreFiltersObj
+const clearMoreFiltersObj = () => {
+  MoreFiltersObj = {}
+}
+const IncotermsCheckAll = ref(false)
+const ServiceCheckAll = ref(false)
+const IncotermsList = ref([
+  {
+    name: 'FOB',
+    number: 2229,
+    checked: false
+  },
+  {
+    name: 'CIF',
+    number: 1000,
+    checked: false
+  }
+])
+const SeiviceList = ref([
+  {
+    name: 'FOB',
+    number: 2229,
+    checked: false
+  },
+  {
+    name: 'CIF',
+    number: 1000,
+    checked: false
+  }
+])
+const IncotermsSearch = (val: any) => {
+  InputForm.value.General.Incoterms = val.data
+  MoreFiltersObj[val.title] = val.data
+}
+const ServiceSearch = (val: any) => {
+  InputForm.value.General.Service = val.data
+  MoreFiltersObj[val.title] = val.data
+}
+</script>
+<template>
+  <div>
+    <el-button class="More_Filters el-button--grey" @click="drawer = true">
+      <span class="iconfont_icon icon_more">
+        <svg class="iconfont" aria-hidden="true">
+          <use xlink:href="#icon-icon_filter_b"></use>
+        </svg>
+      </span>
+      <div class="Filters_title">More Filters</div>
+    </el-button>
+    <el-drawer size="400px" title="More Filters" v-model="drawer">
+      <el-collapse @change="changeCollapse"
+        ><!-- General -->
+        <el-collapse-item class="collapse_item" name="General" v-if="props.isShipment">
+          <template #title>
+            <span class="collapse-title"
+              >General <el-badge class="mark" :value="GeneralBadge" type="warning"
+            /></span>
+          </template>
+          <div class="ETD">
+            <div class="ETD_title">Incoterms</div>
+            <SelectValue
+              :checkAll="IncotermsCheckAll"
+              title="Incoterms"
+              :TransportListItem="IncotermsList"
+              @generalSearch="IncotermsSearch"
+              :Serval="InputForm.General.Incoterms"
+            ></SelectValue>
+          </div>
+          <div class="ETA">
+            <div class="ETD_title">Service</div>
+            <SelectValue
+              :checkAll="ServiceCheckAll"
+              title="Service"
+              :TransportListItem="SeiviceList"
+              @generalSearch="ServiceSearch"
+              :Serval="InputForm.General.Service"
+            ></SelectValue>
+          </div>
+        </el-collapse-item>
+        <!-- Parties -->
+        <el-collapse-item class="collapse_item" name="Parties">
+          <template #title>
+            <span class="collapse-title"
+              >Parties <el-badge class="mark" :value="PartiesBadge" type="warning"
+            /></span>
+          </template>
+          <div class="ETD">
+            <div class="ETD_title">Shipper Name</div>
+            <AutoSelect
+              ASType="contanct"
+              @changeAutoSelect="changeAutoSelectshippername"
+              :ASValue="InputForm.parties.shippername"
+              ASPlaceholder="Please input shipper name"
+            >
+            </AutoSelect>
+          </div>
+          <div class="ETA">
+            <div class="ETD_title">Consignee Name</div>
+            <AutoSelect
+              ASType="contanct"
+              @changeAutoSelect="changeAutoSelectconsigneename"
+              :ASValue="InputForm.parties.consigneename"
+              ASPlaceholder="Please input consignee name"
+            >
+            </AutoSelect>
+          </div>
+          <SelectAutoSelect
+            ref="partSelectTableSelectRef"
+            :AddDateType="AddDateType"
+            :DateTypeoptions="PartyTypeoptions"
+            :Verification="verification"
+            @changeAutoSelectAddType="changeAutoSelectAddType"
+            @changeAutoSelect="changeAutoSelectVal"
+            :selectedPartyTypeoptions="selectedPartyTypeoptions"
+            @delSelect="delSelect"
+            ASPlaceholder="Please input party name"
+          >
+          </SelectAutoSelect>
+          <div
+            class="MoreType"
+            @click="AddType('party')"
+            v-if="AddDateType.length != PartyTypeoptions.length"
+          >
+            + More Party Type
+          </div>
+        </el-collapse-item>
+        <!-- Places -->
+        <el-collapse-item class="collapse_item" name="Places">
+          <template #title
+            ><span class="collapse-title"
+              >Places<el-badge class="mark" :value="PlacesBadge" type="warning" /></span
+          ></template>
+          <div class="ETD">
+            <div class="ETD_title">Origin</div>
+            <SelectTable :searchInput="InputForm.palces.origin" @check="checkorigin" />
+          </div>
+          <div class="ETA">
+            <div class="ETD_title">Destination</div>
+            <SelectTable :searchInput="InputForm.palces.destination" @check="checkdestination" />
+          </div>
+          <SelectTableSelect
+            ref="placeSelectTableSelectRef"
+            :AddDateType="AddDatePlaceType"
+            :DateTypeoptions="PlaceTypeoptions"
+            :Verification="placesVerification"
+            @changeAutoSelectAddType="changeAutoSelectPlacesAddType"
+            @changeAutoSelect="changeAutoSelectVal"
+            :selectedPartyTypeoptions="selectedPlacesTypeoptions"
+            @delSelect="delPlacesSelect"
+            ASPlaceholder="Please input places name"
+          >
+          </SelectTableSelect>
+          <!-- More Place Type -->
+          <div
+            class="MoreType"
+            @click="AddType('place')"
+            v-if="AddDatePlaceType.length != PlaceTypeoptions.length"
+          >
+            + More Place Type
+          </div>
+        </el-collapse-item>
+        <!-- Transportation -->
+        <el-collapse-item class="collapse_item" name="Transportation">
+          <template #title
+            ><span class="collapse-title"
+              >Transportation
+              <el-badge class="mark" :value="TransportationBadge" type="warning" /></span
+          ></template>
+          <div class="ETD">
+            <div class="ETD_title">Vessel</div>
+            <AutoSelect
+              ASType="vessel"
+              @changeAutoSelect="changeAutoSelectvessel"
+              class="input_change"
+              :ASValue="InputForm.transportation.vessel"
+              ASPlaceholder="Please input vessel name or code"
+            >
+            </AutoSelect>
+          </div>
+          <div class="ETA">
+            <div class="ETD_title">Voyage/Flight</div>
+            <AutoSelect
+              ASType="vessel"
+              @changeAutoSelect="changeAutoSelectvoyage"
+              class="input_change"
+              :ASValue="InputForm.transportation.voyage"
+              ASPlaceholder="Please input voyage or flight no."
+            ></AutoSelect>
+          </div>
+        </el-collapse-item>
+        <!-- Others -->
+        <el-collapse-item class="collapse_item" name="Others">
+          <template #title><span class="collapse-title">Others</span></template>
+        </el-collapse-item>
+      </el-collapse>
+      <div class="more_bottom">
+        <el-button class="reset" type="default" @click="clearrest">
+          <span class="iconfont_icon select_icon">
+            <svg class="iconfont" aria-hidden="true">
+              <use xlink:href="#icon-icon_reset_b"></use>
+            </svg>
+          </span>
+          Reset
+        </el-button>
+        <el-button class="reset el-button--dark" style="margin-left: 8px" @click="SearchMore">
+          <span class="iconfont_icon select_icon search_icon">
+            <svg class="iconfont" aria-hidden="true">
+              <use xlink:href="#icon-icon_search_b"></use>
+            </svg>
+          </span>
+          Search
+        </el-button>
+      </div>
+    </el-drawer>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.icon_more {
+  margin-left: 8px;
+  margin-right: 0;
+}
+
+.icon_delete {
+  fill: var(--color-danger);
+  cursor: pointer;
+}
+
+.More_Filters {
+  display: flex;
+  align-items: center;
+  height: 32px;
+  font-size: var(--font-size-3);
+  margin-left: 8px;
+  width: 116px;
+}
+
+.More_Filters:hover {
+  .Filters_title {
+    color: var(--color-theme);
+  }
+}
+
+.select_icon {
+  margin-right: 8px;
+}
+
+.Filters_title {
+  margin: 0 8px;
+}
+
+:deep(.el-drawer__header) {
+  background-color: var(--color-table-header-bg);
+  display: flex;
+  align-items: center;
+  height: 64px;
+  padding: 0;
+  padding-left: 17.12px;
+  margin-bottom: 0;
+  color: var(--color-neutral-1);
+}
+
+:deep(.el-drawer__title) {
+  font-size: var(--font-size-6);
+  font-weight: bold;
+}
+
+:deep(.el-drawer__close-btn) {
+  font-size: var(--font-size-4);
+  color: var(--icon-color-black);
+  margin-right: 24px;
+  padding: 0;
+}
+
+:deep(.el-drawer__body) {
+  padding: 0;
+  position: relative;
+}
+
+.collapse-title {
+  flex: 1 0 90%;
+  order: 1;
+  text-align: left;
+}
+
+:deep(.el-collapse-item__header) {
+  border-bottom: none;
+  height: 48px;
+  color: var(--icon-color-blac);
+  font-size: var(--font-size-4);
+  font-weight: bold;
+  padding-left: 16px;
+}
+
+:deep(.el-collapse-item__wrap) {
+  border-bottom: none;
+  background-color: var(--more-filters-background-color);
+}
+
+.ETD {
+  margin: 8px 16px;
+}
+
+.ETA {
+  margin: 16px 16px;
+}
+
+.ETD_title {
+  font-size: var(--font-size-2);
+  color: var(--color-neutral-2);
+}
+
+.Date_Title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.MoreType {
+  color: var(--color-accent-2);
+  padding: 0 0 16px 16px;
+  cursor: pointer;
+}
+
+.AddType {
+  background-color: var(--addparties-background-color);
+  margin: 0 16px 8px 16px;
+  padding: 8px;
+  border-radius: var(--border-radius-6);
+}
+
+.more_bottom {
+  display: flex;
+  align-items: center;
+  bottom: 0;
+  height: 64px;
+  border-top: 1px solid var(--color-border-top);
+  width: 400px;
+  padding: 16px;
+}
+
+.reset {
+  width: 180px;
+  display: flex;
+  align-items: center;
+  height: 40px;
+  justify-content: center;
+  border: 1px solid var(--color-accent-13);
+  border-radius: var(--border-radius-6);
+}
+
+.AlertInput :deep(.el-select__wrapper) {
+  box-shadow: 0 0 0 0.5px var(--color-danger);
+}
+
+:deep(.el-drawer__body) {
+  padding: 0 !important;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  overflow-x: hidden;
+}
+
+:deep(.el-overlay) {
+  background-color: transparent;
+}
+:deep(.el-drawer__close-btn) {
+  margin-right: 0;
+}
+</style>

+ 283 - 0
src/components/MoreFilters/src/components/SelectValue.vue

@@ -0,0 +1,283 @@
+<script setup lang="ts">
+import { ref, watch, computed } from 'vue'
+import type { DropdownInstance } from 'element-plus'
+
+interface ListItem {
+  name: string
+  number: number
+  checked: boolean
+}
+interface Props {
+  TransportListItem: ListItem[]
+  title: String
+  Serval: String
+  checkAll: boolean
+}
+const props = withDefaults(defineProps<Props>(), {
+  checkAll: false
+})
+const TransportList = ref(props.TransportListItem)
+const Title = ref(props.title)
+const Serval = ref(props.Serval)
+const checkAll = ref(props.checkAll)
+watch(
+  () => props.TransportListItem,
+  (current) => {
+    TransportList.value = current
+  }
+)
+watch(
+  () => props.Serval,
+  (current) => {
+    Serval.value = current
+  }
+)
+watch(
+  () => props.checkAll,
+  (current) => {
+    checkAll.value = current
+  }
+)
+
+const dropdown1 = ref<DropdownInstance>()
+let checkedCount: any[] = []
+const TotalAll = computed(() => {
+  var total_sum = 0
+  if (TransportList.value != undefined) {
+    TransportList.value.map((item) => {
+      total_sum += item.number
+    })
+  }
+  return total_sum
+})
+
+const handleCheckAllChange = (val: any) => {
+  checkedCount = []
+  TransportList.value.forEach((item: any) => {
+    if (val) {
+      item.checked = true
+      checkedCount.push(item.name)
+    } else {
+      item.checked = false
+      checkedCount = []
+    }
+  })
+}
+const handleCheckedTransportChange = (value: any, checked: any, index: any) => {
+  if (checked) {
+    checkedCount.push(value)
+    const map = new Map()
+    checkedCount.forEach((item) => map.set(item, true))
+    checkedCount = [...map.keys()]
+  } else {
+    if (checkedCount.length == 1) {
+      checkedCount.splice(0, 1)
+    } else {
+      checkedCount.splice(index, 1)
+    }
+  }
+  checkAll.value = checkedCount.length === TransportList.value.length
+}
+
+// 清除选中
+const clearList = () => {
+  checkAll.value = false
+  TransportList.value.forEach((item: any) => {
+    item.checked = false
+  })
+  changedata.value = ''
+  checkedCount = []
+}
+const emit = defineEmits(['generalSearch'])
+const changedata = ref()
+//点击搜索
+const TransportSearch = (visible: any) => {
+  if (checkedCount.length == TransportList.value.length) {
+    changedata.value = 'All'
+  } else {
+    changedata.value = checkedCount.join(', ')
+  }
+  const TransportData = {
+    title: Title.value,
+    data: changedata.value
+  }
+  Serval.value = changedata.value
+  emit('generalSearch', TransportData)
+  if (!dropdown1.value) return
+  if (visible) {
+    dropdown1.value.handleClose()
+  } else {
+    dropdown1.value.handleOpen()
+  }
+}
+</script>
+<template>
+  <div class="select">
+    <el-dropdown ref="dropdown1" trigger="click" :hide-on-click="false">
+      <div class="el-dropdown-link">
+        <div v-if="Serval == 'Please Select Date Range' || Serval == ''" class="select_title">
+          Please Select Date Range
+        </div>
+        <div v-else class="select_title_2">{{ Serval }}</div>
+        <span class="iconfont_icon">
+          <svg class="iconfont" aria-hidden="true">
+            <use xlink:href="#icon-icon_dropdown_b"></use>
+          </svg>
+        </span>
+      </div>
+      <template #dropdown>
+        <div class="dropdownwidth">
+          <div class="title">{{ Title }} {{ checkAll }}</div>
+          <el-dropdown-menu>
+            <el-dropdown-item>
+              <el-checkbox v-model="checkAll" class="checkbox" @change="handleCheckAllChange">
+                <div class="checkbox_title">Select All</div>
+                <div class="checkbox_number">({{ TotalAll }})</div>
+              </el-checkbox>
+            </el-dropdown-item>
+            <el-divider></el-divider>
+            <el-dropdown-item v-for="(item, index) in TransportList" :key="index">
+              <el-checkbox
+                :value="item.name"
+                v-model="item.checked"
+                class="checkbox"
+                @change="handleCheckedTransportChange(item.name, item.checked, index)"
+              >
+                <div class="checkbox_title">
+                  {{ item.name }}
+                </div>
+                <div class="checkbox_number">({{ item.number }})</div>
+              </el-checkbox>
+            </el-dropdown-item>
+            <div class="transport_bottom">
+              <div>
+                <el-button class="clear" type="default" @click="clearList">Reset</el-button>
+              </div>
+              <div>
+                <el-button class="search el-button--dark" @click="TransportSearch">OK</el-button>
+              </div>
+            </div>
+          </el-dropdown-menu>
+        </div>
+      </template>
+    </el-dropdown>
+  </div>
+</template>
+<style lang="scss" scoped>
+.iconfont_icon {
+  margin-right: 8px;
+}
+.iconfont_select {
+  width: 17px;
+  height: 17px;
+}
+.select {
+  cursor: pointer;
+  width: 368px;
+  height: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  background-color: white;
+  border: 1px solid var(--color-border);
+  border-radius: var(--border-radius-6);
+}
+.select:hover {
+  border: 1px solid var(--color-theme);
+}
+.el-dropdown-link {
+  width: 360px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.select_title {
+  font-size: var(--font-size-3);
+  font-weight: 400;
+  margin-left: 8.53px;
+  color: var(--color-neutral-3);
+}
+.select_title_2 {
+  font-size: var(--font-size-3);
+  font-weight: 400;
+  margin-left: 8.53px;
+  color: var(--color-neutral-1);
+}
+.title {
+  font-weight: 700;
+  font-size: var(--font-size-5);
+  background-color: var(--color-header-bg);
+  height: 48px;
+  display: flex;
+  align-items: center;
+  padding-left: 16px;
+}
+.checkbox {
+  width: 216px;
+  font-weight: 400;
+  font-size: var(--font-size-3);
+  padding: 0 12px;
+  height: 40px;
+}
+:deep(.el-popper__arrow, .el-popper__arrow:before) {
+  height: 0;
+  width: 0;
+}
+:deep(.el-checkbox__label) {
+  width: 176px;
+  padding-left: 13px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.checkbox_title {
+  color: var(--color-neutral-1);
+}
+.checkbox_number {
+  color: var(--color-neutral-3);
+}
+.transport_bottom {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  height: 48px;
+  border-top: 1px solid var(--color-border);
+  margin-top: 5px;
+  font-weight: 400;
+  font-size: var(--font-size-3);
+}
+.clear {
+  width: 81px;
+  height: 32px;
+  margin-right: 7.82px;
+}
+.search {
+  width: 86px;
+  height: 32px;
+  margin-right: 16px;
+}
+.search:hover {
+  color: var(--color-theme);
+}
+:deep(.el-dropdown-menu__item:hover) {
+  background-color: var(--border-hover-color);
+  border-radius: var(--border-radius-6);
+  border-color: var(--border-hover-color);
+}
+:deep(.el-dropdown-menu__item) {
+  padding: 0;
+  margin: 10px 16px;
+}
+:deep(.el-dropdown-menu__item:not(.is-disabled):focus) {
+  background-color: var(--border-hover-color);
+  border-radius: var(--border-radius-6);
+  border-color: var(--border-hover-color);
+}
+.dropdownwidth {
+  width: 360px;
+}
+.el-divider--horizontal {
+  margin: 8px 0;
+  border-top-color: var(--color-border);
+}
+</style>

+ 111 - 0
src/components/ScoringGrade/components/DialogColorful.vue

@@ -0,0 +1,111 @@
+<script setup lang="ts">
+import { ref } from 'vue'
+const props = defineProps({
+  colorfulSrc: String,
+  isshowexpression: Boolean,
+  isshowDetails: Boolean
+})
+const inputdetails = ref('')
+const emits = defineEmits(['submitDetails'])
+const submitDetails = (val: any) => {
+  emits('submitDetails', val)
+}
+</script>
+<template>
+  <div class="colorfulflex">
+    <div v-if="props.isshowexpression" class="dialogcolorful">
+      <div class="dialogue">
+        <img :src="props.colorfulSrc" />
+      </div>
+      <div class="vector">
+        <img class="vector_img" src="/src/styles/images/bubble_corner_colorful.png" />
+      </div>
+    </div>
+    <div v-if="props.isshowDetails" class="dialogcolorful submit">
+      <div class="dialogue dialoguesubmit">
+        <el-input
+          class="inputdetails"
+          v-model="inputdetails"
+          style="width: 554px"
+          :rows="4"
+          type="textarea"
+          placeholder="We look forward to hearing from you.  thank you for helping to build a better customer system"
+        />
+        <div class="button_submit">
+          <el-button class="submit_button el-button--dark" @click="submitDetails(inputdetails)"
+            >Submit</el-button
+          >
+        </div>
+      </div>
+      <div class="vector vector_submit">
+        <img class="vector_img" src="/src/styles/images/bubble_corner_colorful.png" />
+      </div>
+    </div>
+  </div>
+</template>
+<style lang="scss" scoped>
+.colorfulflex {
+  display: flex;
+  justify-content: end;
+  margin-bottom: 8px;
+}
+.dialogcolorful {
+  width: 56px;
+  display: flex;
+  flex-direction: column;
+}
+.submit {
+  width: 570px;
+  margin: auto;
+}
+.dialogue {
+  color: var(--tag-info-text-color);
+  font-size: var(--font-size-4);
+  border-radius: var(--border-radius-12) var(--border-radius-12) 0 var(--border-radius-12);
+  background: linear-gradient(251deg, rgba(242, 244, 247) 0%, rgba(255, 237, 230) 100%);
+  padding: 8px;
+  width: 56px;
+  height: 56px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.dialoguesubmit {
+  width: 570px;
+  display: block;
+  height: auto;
+}
+.vector {
+  width: 56px;
+  height: 8px;
+  display: flex;
+  justify-content: end;
+}
+.vector_submit {
+  width: 570px;
+}
+.vector_img {
+  vertical-align: top;
+}
+:deep(.el-textarea) {
+  .el-textarea__inner {
+    resize: none; // 去除右下角图标
+    padding: 5px 7px 5px 10px;
+  }
+}
+.submit_button {
+  width: 180px;
+  height: 40px;
+}
+.button_submit {
+  width: 553px;
+  margin-top: 9.51px;
+  display: flex;
+  justify-content: end;
+}
+:deep(.el-button > span) {
+  color: #ffffff !important;
+  font-weight: 400;
+  font-size: var(--font-size-3);
+}
+</style>

+ 218 - 0
src/components/ScoringGrade/components/DialogUe.vue

@@ -0,0 +1,218 @@
+<script setup lang="ts">
+import { ref } from 'vue'
+
+const props = defineProps({
+  content: String,
+  dialogWidth: String,
+  isShowAngry: Boolean,
+  isShowSmile: Boolean
+})
+const checkboxGroup1 = ref([])
+const evaluate = [
+  'Complete funtionality',
+  'Accurate information',
+  'Visualization of shipments',
+  'Easy to use',
+  'Performance'
+]
+const emits = defineEmits(['changeAngryDetails', 'changeSmileRadio'])
+const changebuttonbox = () => {
+  emits('changeAngryDetails')
+}
+const Aspects = ref([
+  'Highly Dissatisfied',
+  'Dissatisfied',
+  'Neutral',
+  'Satisfied',
+  'Highly Satisfied'
+])
+
+interface smileAspectsItem {
+  title: string
+  proposal: Array<string>
+  radio: string
+}
+const smileAspects = ref<smileAspectsItem[]>([])
+smileAspects.value = [
+  {
+    title: 'Complete funtionality',
+    proposal: ['Highly Dissatisfied', 'Dissatisfied', 'Neutral', 'Satisfied', 'Highly Satisfied'],
+    radio: ''
+  },
+  {
+    title: 'Accurate information',
+    proposal: ['Highly Dissatisfied', 'Dissatisfied', 'Neutral', 'Satisfied', 'Highly Satisfied'],
+    radio: ''
+  },
+  {
+    title: 'Visualization of shipments',
+    proposal: ['Highly Dissatisfied', 'Dissatisfied', 'Neutral', 'Satisfied', 'Highly Satisfied'],
+    radio: ''
+  },
+  {
+    title: 'Easy to use',
+    proposal: ['Highly Dissatisfied', 'Dissatisfied', 'Neutral', 'Satisfied', 'Highly Satisfied'],
+    radio: ''
+  },
+  {
+    title: 'Performance',
+    proposal: ['Highly Dissatisfied', 'Dissatisfied', 'Neutral', 'Satisfied', 'Highly Satisfied'],
+    radio: ''
+  }
+]
+let SmileObj: any = {}
+const changeSmileRadio = (title: any, value: any) => {
+  SmileObj[title] = value
+  emits('changeSmileRadio', SmileObj)
+}
+</script>
+<template>
+  <div style="margin-bottom: 8px">
+    <div class="dialogue" :style="{ width: props.dialogWidth }">
+      {{ props.content }}
+      <div v-if="props.isShowAngry" class="dialogflex">
+        <el-checkbox-group v-model="checkboxGroup1" size="large">
+          <el-checkbox-button
+            @change="changebuttonbox"
+            v-for="item in evaluate"
+            :key="item"
+            :value="item"
+          >
+            {{ item }}
+          </el-checkbox-button>
+        </el-checkbox-group>
+      </div>
+      <div v-if="props.isShowSmile">
+        <div class="smile_flex">
+          <div class="smile_title_left"></div>
+          <div class="smile_title_right">
+            <div class="smile_title" v-for="item in Aspects" :key="item">
+              {{ item }}
+            </div>
+          </div>
+        </div>
+        <div class="smile_content_flex" v-for="(item, index) in smileAspects" :key="index">
+          <div class="smile_title_left content_left">{{ item.title }}</div>
+          <div class="smile_title_right content_right">
+            <el-radio-group v-model="item.radio" @change="changeSmileRadio(item.title, item.radio)">
+              <el-radio
+                class="smile_radio"
+                v-for="proposal in item.proposal"
+                :value="proposal"
+                :key="proposal"
+              ></el-radio>
+            </el-radio-group>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="vector"><img class="vector_img" src="/src/styles/images/bubble_corner.png" /></div>
+  </div>
+</template>
+<style lang="scss" scoped>
+.dialogflex {
+  display: flex;
+  margin-top: 8px;
+}
+.dialogue {
+  color: var(--tag-info-text-color);
+  font-size: var(--font-size-4);
+  border-radius: var(--border-radius-12) var(--border-radius-12) var(--border-radius-12) 0;
+  background-color: #f2f4f7;
+  padding: 8px;
+}
+.vector {
+  height: 8px;
+}
+.vector_img {
+  vertical-align: top;
+}
+:deep(.el-checkbox-button__inner) {
+  color: var(--tag-info-text-color);
+  font-size: var(--font-size-3);
+  font-weight: 400;
+  padding: 0;
+  width: 180px;
+  height: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid var(--color-border);
+  border-radius: var(--border-radius-6);
+  margin-bottom: 8px;
+}
+:deep(.el-checkbox-button__inner:hover) {
+  color: var(--color-theme);
+  background-color: var(--color-btn-default-bg-hover);
+  border-color: var(--color-btn-default-bg-hover);
+}
+:deep(.el-checkbox-button.is-focus .el-checkbox-button__inner) {
+  border-color: transparent;
+}
+:deep(.el-checkbox-button:first-child .el-checkbox-button__inner) {
+  border-left: 1px solid var(--color-border);
+  border-top-left-radius: var(--border-radius-6);
+  border-bottom-left-radius: var(--border-radius-6);
+}
+:deep(.el-checkbox-button:last-child .el-checkbox-button__inner) {
+  border-top-right-radius: var(--border-radius-6);
+  border-bottom-right-radius: var(--border-radius-6);
+}
+:deep(.el-checkbox-button:nth-child(3n + 1)) {
+  margin-right: 8px;
+}
+:deep(.el-checkbox-button:nth-child(3n + 2)) {
+  margin-right: 8px;
+}
+:deep(.el-checkbox-button.is-checked .el-checkbox-button__inner) {
+  color: #ffffff;
+  background-color: var(--color-theme);
+  border-color: var(--color-theme);
+}
+.smile_flex {
+  display: flex;
+  margin-top: 20px;
+}
+.smile_title_left {
+  width: 176px;
+}
+.smile_title_right {
+  display: flex;
+}
+.smile_title {
+  width: 75.4px;
+  font-size: var(--font-size-2);
+  line-height: 16px;
+  font-weight: 400;
+  display: flex;
+  justify-content: center;
+  align-items: end;
+  text-align: center;
+}
+.smile_content_flex {
+  display: flex;
+  margin-top: 8px;
+}
+.content_left {
+  height: 41px;
+  background-color: #fff;
+  font-weight: 400;
+  font-size: var(--font-size-3);
+  border-radius: 6px 0 0 6px;
+  display: flex;
+  align-items: center;
+  padding-left: 7px;
+}
+.smile_radio {
+  width: 75.4px;
+  display: flex;
+  justify-content: center;
+}
+.content_right {
+  background-color: #e0e2e6;
+  border-radius: 0 6px 6px 0;
+}
+.el-radio {
+  margin-right: 0;
+}
+</style>

+ 1 - 0
src/components/ScoringGrade/index.ts

@@ -0,0 +1 @@
+export { default } from './src/ScoringGrade.vue'

+ 293 - 0
src/components/ScoringGrade/src/ScoringGrade.vue

@@ -0,0 +1,293 @@
+<script setup lang="ts">
+import { ref } from 'vue'
+import DialogUe from '../components/DialogUe.vue'
+import DialogColorful from '../components/DialogColorful.vue'
+
+const isShow = ref(true)
+const visible = ref(false)
+const isLoaded = ref(false)
+const isShowAngry = ref(false)
+const isShowSmile = ref(false)
+const isLoaded_share = ref(false)
+const isshowexpression = ref(true)
+const isshowexpression_details = ref(false)
+const isshowDetails_submit = ref(false)
+const isshowDetails = ref(true)
+interface AvaterItem {
+  src: string
+  itemsrc: string
+  itemtext: string
+  expression: string
+  proposal: string
+}
+const avater = ref<AvaterItem[]>([])
+const colorfulSrc = ref()
+const dialogcontent = ref()
+const angryproposal = ref()
+const smileproposal = ref()
+const clickSrc = ref('/src/styles/images/score_normal.png')
+avater.value = [
+  {
+    src: '/src/styles/images/score_angry.png',
+    itemsrc: '/src/styles/images/angry_2.png',
+    itemtext: 'We are so sorry for the inconveniences. We value your experience immensely. ',
+    expression: 'angry',
+    proposal: 'Could you please tell us which aspects of the system you are dissatisfied with?'
+  },
+  {
+    src: '/src/styles/images/score_sad.png',
+    itemsrc: '/src/styles/images/sad_2.png',
+    itemtext: 'We are so sorry for the inconveniences. We value your experience immensely. ',
+    expression: 'angry',
+    proposal: 'Could you please tell us which aspects of the system you are dissatisfied with?'
+  },
+  {
+    src: '/src/styles/images/score_smile.png',
+    itemsrc: '/src/styles/images/smile_2.png',
+    itemtext: 'Thank you for sharing your thoughts with us. We value your experience greatly.',
+    expression: 'smile',
+    proposal: 'Could you share what aspects you liked and what could be improved ?'
+  },
+  {
+    src: '/src/styles/images/score_hhh.png',
+    itemsrc: '/src/styles/images/hhh_2.png',
+    itemtext: 'Thank you very much for giving us a satisfied rating on our service or system.',
+    expression: 'happy',
+    proposal: 'We are curious to learn more about what specifically made you feel satisfied. '
+  },
+  {
+    src: '/src/styles/images/score_happy.png',
+    itemsrc: '/src/styles/images/happy_2.png',
+    itemtext: 'Thank you very much for giving us a satisfied rating on our service or system.',
+    expression: 'happy',
+    proposal: 'We are curious to learn more about what specifically made you feel satisfied. '
+  }
+]
+const dialogVisible = ref(false)
+
+// 控制表情normal的显隐
+const showPopver = () => {
+  isShow.value = false
+}
+// 控制popover的显隐
+const showScore = (item: any) => {
+  visible.value = false
+  dialogVisible.value = true
+  clickSrc.value = item.itemsrc
+  isShow.value = true
+  colorfulSrc.value = item.itemsrc
+  setTimeout(() => {
+    isLoaded.value = true
+    dialogcontent.value = item.itemtext
+    if (item.expression == 'angry') {
+      setTimeout(() => {
+        isShowAngry.value = true
+        angryproposal.value = item.proposal
+      }, 1500)
+    } else if (item.expression == 'smile') {
+      setTimeout(() => {
+        isShowSmile.value = true
+        smileproposal.value = item.proposal
+      }, 1500)
+    } else {
+      setTimeout(() => {
+        isShowAngry.value = true
+        angryproposal.value = item.proposal
+      }, 1500)
+    }
+  }, 1000)
+}
+const avatarClick = () => {
+  visible.value = true
+  isshowDetails.value = true
+}
+//关闭对话框后,隐藏有动画的对话框
+const closeDialog = () => {
+  isLoaded.value = false
+  isLoaded.value = false
+  isLoaded_share.value = false
+  isShowAngry.value = false
+  isshowDetails.value = false
+  isShowSmile.value = false
+  isshowexpression_details.value = false
+}
+//生气表情,选择建议后显示对话
+const changeAngryDetails = () => {
+  setTimeout(() => {
+    isLoaded_share.value = true
+    setTimeout(() => {
+      isshowexpression_details.value = true
+    }, 1500)
+  }, 1500)
+}
+// smile提交后显示对话
+const changeSmileRadio = (val: any) => {
+  if (Object.keys(val).length == 5) {
+    changeAngryDetails()
+  }
+}
+// 提交details
+const submitDetails = (val: any) => {
+  console.log(val)
+  isshowDetails_submit.value = true
+}
+</script>
+<template>
+  <div class="scoring" :style="[{ display: isShow ? 'flex' : 'none' }]">
+    <el-popover
+      @show="showPopver"
+      :visible="visible"
+      placement="left"
+      trigger="click"
+      :width="367"
+      popper-class="popver_class"
+    >
+      <template #reference>
+        <el-avatar
+          @click="avatarClick"
+          :style="[{ display: isShow ? 'block' : 'none' }]"
+          :size="46"
+          shape="square"
+          :src="clickSrc"
+        />
+      </template>
+      <div class="flex">
+        <el-popover
+          placement="top"
+          :width="260"
+          trigger="hover"
+          v-for="(item, index) in avater"
+          :key="index"
+          content="How satisfied are you with this system?"
+        >
+          <template #reference>
+            <div class="score">
+              <el-avatar @click="showScore(item)" :size="40" shape="square" :src="item.src" />
+            </div>
+          </template>
+        </el-popover>
+      </div>
+    </el-popover>
+    <el-dialog
+      v-model="dialogVisible"
+      title="Hi,Caroline!"
+      :destroy-on-close="true"
+      @close="closeDialog"
+      width="640"
+      :modal="false"
+      top="0"
+      class="scoreDialog"
+      custom-class="my-dialog"
+      :close-on-click-modal="false"
+    >
+      <div v-if="isshowDetails">
+        <DialogUe content="How satisfied are you with this system ?" dialogWidth="298px"></DialogUe>
+        <DialogColorful
+          :colorfulSrc="colorfulSrc"
+          :isshowexpression="isshowexpression"
+        ></DialogColorful>
+        <transition name="fade">
+          <DialogUe v-if="isLoaded" :content="dialogcontent" dialogWidth="573px"></DialogUe>
+        </transition>
+        <transition name="fade" v-if="isShowAngry">
+          <DialogUe
+            :content="angryproposal"
+            :isShowAngry="isShowAngry"
+            @changeAngryDetails="changeAngryDetails"
+            dialogWidth="573px"
+          ></DialogUe>
+        </transition>
+        <transition name="fade" v-if="isShowSmile">
+          <DialogUe
+            :isShowSmile="isShowSmile"
+            @changeSmileRadio="changeSmileRadio"
+            :content="smileproposal"
+            dialogWidth="573px"
+          ></DialogUe>
+        </transition>
+        <transition name="fade" v-if="isLoaded_share">
+          <DialogUe
+            content="Would you like to share more details with us?"
+            dialogWidth="334px"
+          ></DialogUe>
+        </transition>
+        <transition name="fade" v-if="isshowexpression_details">
+          <DialogColorful
+            :isshowDetails="isshowexpression_details"
+            @submitDetails="submitDetails"
+          ></DialogColorful>
+        </transition>
+      </div>
+      <el-result
+        class="result"
+        v-if="isshowDetails_submit"
+        icon="success"
+        title="Submit Successful"
+      >
+        <template #icon>
+          <el-image src="/src/styles/images/submit_successful.png" />
+        </template>
+        <template #sub-title>
+          <div class="sub_title_text">Apologize once again for your experience.</div>
+          <div class="sub_title_text">
+            We are committed to working hard to provide better services.
+          </div>
+        </template>
+      </el-result>
+    </el-dialog>
+  </div>
+</template>
+
+<style lang="scss">
+.scoring {
+  width: 64px;
+  height: 64px;
+  border-radius: 12px 0 0 12px;
+  background-color: #fff;
+  position: absolute;
+  z-index: 2013;
+  right: 0;
+  bottom: 168px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.el-avatar {
+  background-color: #fff;
+  cursor: pointer;
+}
+.flex {
+  display: flex;
+  height: 64px;
+  align-items: center;
+}
+.score {
+  margin: 0 16px;
+}
+.el-popover.popver_class {
+  border-radius: 12px 0 0 12px !important;
+  box-shadow: none;
+  filter: drop-shadow(-2px 2px 12px rgba(0, 0, 0, 0.15));
+  right: 0 !important;
+}
+.el-dialog.scoreDialog {
+  position: absolute;
+  margin-bottom: 0;
+  right: 0;
+  bottom: 168px;
+}
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 3s;
+}
+.fade-enter-from,
+.fade-leave-to {
+  opacity: 0;
+}
+.sub_title_text {
+  color: var(--color-neutral-3);
+}
+.result {
+  height: 578px;
+}
+</style>

+ 1 - 0
src/components/SeeAllIcon/index.ts

@@ -0,0 +1 @@
+export { default } from './src/SeeAllIcon.vue'

+ 45 - 0
src/components/SeeAllIcon/src/SeeAllIcon.vue

@@ -0,0 +1,45 @@
+<script setup lang="ts">
+const isCollapse = defineModel<boolean>()
+const emits = defineEmits<{ collapse: [boolean] }>()
+const handleSeeAll = () => {
+  isCollapse.value = !isCollapse.value
+  // 使用nextTick来确保父组件能够在子组件的值更新后获取到最新的值
+  nextTick(() => {
+    emits('collapse', isCollapse.value as boolean)
+  })
+}
+</script>
+
+<template>
+  <div class="see-all-icon" @click="handleSeeAll">
+    <span class="btn">See All</span>
+    <span
+      class="icon font_family icon-icon_dropdown__line_b"
+      :class="{ 'is-rotate': isCollapse }"
+    ></span>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.see-all-icon {
+  display: inline-block;
+  cursor: pointer;
+  & > .btn {
+    margin-left: 8px;
+    font-size: 14px;
+    font-weight: 400;
+    color: var(--color-theme);
+  }
+  & > .icon {
+    display: inline-block !important;
+    margin-left: 2px;
+    margin-top: -2px;
+    transform: rotate(0deg);
+    transition: all 0.3s;
+    color: var(--color-theme);
+    &.is-rotate {
+      transform: rotate(180deg) !important;
+    }
+  }
+}
+</style>

+ 1 - 0
src/components/SelectTable/index.ts

@@ -0,0 +1 @@
+export { default } from './src/SelectTable.vue'

+ 114 - 0
src/components/SelectTable/src/SelectTable copy.vue

@@ -0,0 +1,114 @@
+<script setup lang="ts" name="SelTable">
+
+const emit = defineEmits(['check', 'input'])
+
+const props = defineProps({
+  value: {
+    type: Array,
+    default: () => []
+  },
+  addTagOnKeys: {
+    type: Array,
+    default: () => []
+  },
+  readOnly: {
+    type: Boolean,
+    default: false
+  },
+})
+
+const tagInputRef: any = ref(null)
+const newTag = ref('')
+const innerTags = ref([...props.value])
+
+watch(
+  () => props.value,
+  () => {
+    innerTags.value = [...props.value]
+  }
+)
+
+function focusTagInput() {
+  if (props.readOnly || !tagInputRef.value) {
+    return
+  } else {
+    tagInputRef.value.focus()
+  }
+}
+
+function inputTag(ev: any) {
+  newTag.value = ev.target.value
+}
+function remove(index: number) {
+  innerTags.value.splice(index, 1)
+  tagChange()
+}
+function addNew(e: any) {
+  if (e && (!props.addTagOnKeys.includes(e.keyCode)) && (e.type !== 'blur')) {
+    return
+  }
+  if (e) {
+    e.stopPropagation()
+    e.preventDefault()
+  }
+  let addSuccess = false
+  if (newTag.value.includes(',')) {
+    newTag.value.split(',').forEach(item => {
+      if (addTag(item.trim())) {
+        addSuccess = true
+      }
+    })
+  } else {
+    if (addTag(newTag.value.trim())) {
+      addSuccess = true
+    }
+  }
+  if (addSuccess) {
+    tagChange()
+    newTag.value = ''
+  }
+}
+function addTag(tag: any) {
+  tag = tag.trim()
+  if (tag && !innerTags.value.includes(tag)) {
+    innerTags.value.push(tag)
+    return true
+  }
+  return false
+}
+
+function removeLastTag() {
+  if (newTag.value) {
+    return
+  }
+  innerTags.value.pop()
+  tagChange()
+}
+function tagChange() {
+  emit('input', innerTags.value)
+}
+
+
+</script>
+<template>
+  <div class="el-input el-input--suffix el-tooltip__trigger" @click="focusTagInput">
+    <div class="el-input__wrapper">
+      <el-space>
+        <template v-for="(tag, idx) in innerTags" :key="tag">
+          <el-tag v-bind="$attrs" type="info" size="small" round :closable="!readOnly" :disable-transitions="false"
+            @close="remove(idx)">
+            {{ tag }}
+          </el-tag>
+        </template>
+        <input v-if="!readOnly" ref="tagInputRef" class="el-input__inner" @input="inputTag" :value="newTag"
+          @keydown.delete.stop="removeLastTag" @keydown="addNew" @blur="addNew" />
+      </el-space>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.el-input__wrapper {
+  justify-content: flex-start;
+}
+</style>

+ 341 - 0
src/components/SelectTable/src/SelectTable.vue

@@ -0,0 +1,341 @@
+<script setup lang="ts" name="SelTable">
+import _ from 'lodash'
+import { reactive, ref, onMounted, watch } from 'vue'
+import { ElMessage } from 'element-plus'
+
+const emit = defineEmits(['check', 'input'])
+const props = defineProps({
+  poverWidth: {
+    type: Number,
+    default: 380
+  },
+  searchInput: {
+    type: Array,
+    default: () => []
+  },
+  disabled: {
+    type: Boolean,
+    default: false
+  },
+  keyVal: {
+    type: String,
+    default: 'city'
+  }
+})
+
+const searchVal = ref(null)
+const innerTags: any = ref([])
+const tagInputRef: any = ref(null)
+
+watch(
+  () => props.searchInput,
+  (current) => {
+    innerTags.value = current
+  },
+  {
+    deep: true,
+    immediate: true
+  }
+)
+// 响应数据
+const state: any = reactive({
+  poverShow: false,
+  currentPage: 1,
+  pageSize: 10,
+  total: 0,
+  activeRowIndex: '',
+  tableData: [],
+  loading: false
+})
+
+// 点击行
+const handleRowClick = (row: any) => {
+  state.poverShow = false
+  if (!innerTags.value.includes(row[props.keyVal])) {
+    innerTags.value.push(row[props.keyVal])
+    state.activeRowIndex = row.id
+    emit('input', innerTags.value)
+    emit('check', innerTags.value)
+  } else {
+    ElMessage({
+      message: 'Cannot add duplicate cities.',
+      type: 'success'
+    })
+  }
+  searchVal.value = null
+}
+const handleSearch = _.debounce((val?) => {
+  state.loading = true
+  searchVal.value = val?.target?.value
+  let filterList: any = []
+  setTimeout(() => {
+    $api
+      .getMoreFiltersTableData({
+        term: searchVal.value ? searchVal.value : '',
+        cp: state.currentPage,
+        ps: state.pageSize,
+        rc: '-1'
+      })
+      .then((res: any) => {
+        if (res.code == 200) {
+          filterList = res.data.searchData
+          state.loading = false
+          filterList = res.data.searchData.filter((p: any) => {
+            return (
+              p.country.toLowerCase().indexOf(searchVal.value.toLowerCase()) > -1 ||
+              p.city.toLowerCase().indexOf(searchVal.value.toLowerCase()) > -1 ||
+              p.uncode.toLowerCase().indexOf(searchVal.value.toLowerCase()) > -1
+            )
+          })
+          state.tableData = filterList
+          state.total = Number(res.data.rc)
+          state.loading = false
+        }
+      })
+  }, 800)
+}, 500)
+// 分页 请求接口
+const handleCurrentChange = () => {
+  state.loading = true
+  let filterList: any = []
+  setTimeout(() => {
+    $api
+      .getMoreFiltersTableData({
+        term: searchVal.value ? searchVal.value : '',
+        cp: state.currentPage,
+        ps: state.pageSize,
+        rc: state.total
+      })
+      .then((res: any) => {
+        if (res.code == 200) {
+          filterList = res.data.searchData
+          state.loading = false
+          filterList = res.data.searchData.filter((p: any) => {
+            return (
+              p.country.toLowerCase().indexOf(searchVal.value.toLowerCase()) > -1 ||
+              p.city.toLowerCase().indexOf(searchVal.value.toLowerCase()) > -1 ||
+              p.uncode.toLowerCase().indexOf(searchVal.value.toLowerCase()) > -1
+            )
+          })
+          state.tableData = filterList
+          state.total = Number(res.data.rc)
+          state.loading = false
+        }
+      })
+  }, 800)
+}
+// 删除
+const remove = (idx: number) => {
+  innerTags.value.splice(idx, 1)
+  emit('input', innerTags.value)
+  emit('check', innerTags.value)
+}
+
+const onInput = () => {
+  tagInputRef.value.focus()
+}
+</script>
+<template>
+  <div>
+    <el-popover
+      v-model:visible="state.poverShow"
+      placement="bottom-start"
+      :teleported="false"
+      :width="props.poverWidth"
+      trigger="click"
+    >
+      <template #reference>
+        <div
+          class="el-input el-input--suffix el-tooltip__trigger"
+          @click="disabled ? null : onInput"
+        >
+          <div class="el-input__wrapper" :class="{ 'is-disabled': disabled }">
+            <el-space :class="[innerTags.length ? 'custom-el-spaceno' : 'custom-el-space']">
+              <template v-for="(item, idx) in innerTags" :key="item">
+                <template v-if="idx <= 2">
+                  <el-tag type="info" closable :disable-transitions="false" @close="remove(idx)">
+                    {{ item }}
+                  </el-tag>
+                </template>
+              </template>
+              <template v-if="innerTags.length && innerTags.length > 3">
+                <el-popover placement="bottom" trigger="hover">
+                  <template #reference>
+                    <el-tag type="info" size="small" round :disable-transitions="false">
+                      +{{ innerTags.length - 3 }}
+                    </el-tag>
+                  </template>
+                  <template #default>
+                    <div style="padding: 5px 5px 0">
+                      <template v-for="(item, idx) in innerTags" :key="item">
+                        <template v-if="idx >= 3">
+                          <el-tag
+                            type="info"
+                            style="
+                              width: 100% !important;
+                              justify-content: space-between;
+                              margin-bottom: 5px;
+                            "
+                            closable
+                            :disable-transitions="false"
+                            @close="remove(idx)"
+                          >
+                            {{ item }}
+                          </el-tag>
+                        </template>
+                      </template>
+                    </div>
+                  </template>
+                </el-popover>
+              </template>
+              <input
+                :disabled="props.disabled"
+                :value="searchVal"
+                ref="tagInputRef"
+                :placeholder="innerTags.length ? '' : 'Please input country/city/uncode'"
+                class="el-input__inner"
+                type="text"
+                @input="handleSearch"
+                @click="handleSearch"
+              />
+            </el-space>
+            <div class="el-input__suffix">
+              <div class="el-input__suffix-inner" v-if="!disabled">
+                <el-icon :class="state.poverShow ? 'reverse' : ''">
+                  <CaretBottom />
+                </el-icon>
+              </div>
+            </div>
+          </div>
+        </div>
+      </template>
+      <el-table
+        :data="state.tableData"
+        border
+        stripe
+        v-loading="state.loading"
+        @row-click="handleRowClick"
+        header-row-class-name="cus-header"
+      >
+        <el-table-column property="country" label="Country" />
+        <el-table-column property="city" label="City" />
+        <el-table-column property="uncode" label="Uncode" />
+      </el-table>
+      <div class="pagination">
+        <span>Total {{ state.total }}</span>
+        <el-pagination
+          v-model:currentPage="state.currentPage"
+          v-model:page-size="state.pageSize"
+          size="small"
+          layout="prev, pager, next"
+          :pager-count="5"
+          :total="state.total"
+          @current-change="handleCurrentChange"
+          @size-change="handleCurrentChange"
+        />
+      </div>
+    </el-popover>
+  </div>
+</template>
+
+<style scoped lang="scss">
+:deep(.el-input) {
+  input {
+    cursor: pointer;
+  }
+
+  .el-input__suffix-inner {
+    i {
+      transition: all 0.3s;
+    }
+
+    .reverse {
+      transform: rotate(-180deg);
+    }
+  }
+
+  .el-input__wrapper {
+    justify-content: space-between;
+  }
+
+  .el-input__wrapper.is-focus {
+    box-shadow: 0 0 0 1px #ffbc79 inset !important;
+  }
+}
+
+:deep(.cus-header) th {
+  background-color: var(--color-table-header-bg) !important;
+}
+
+:deep(.el-table__row) {
+  td {
+    cursor: pointer;
+  }
+}
+
+:deep(.el-table__row:not(.current-row):hover) {
+  td {
+    background-color: #fff1e6 !important;
+  }
+}
+
+:deep(.current-row) {
+  td {
+    background-color: #ffe3cd !important;
+  }
+}
+
+.pagination {
+  display: flex;
+  align-items: center;
+  height: 40px;
+  justify-content: space-between;
+  padding: 0 12px 0 8px;
+
+  > span {
+    font-size: 13px;
+  }
+}
+
+:deep(.el-popper) {
+  border-radius: 12px !important;
+}
+
+:deep(.el-pagination) {
+  .is-active {
+    color: #b57b32 !important;
+  }
+}
+
+:deep(.el-table--fit) {
+  border-top-left-radius: 12px;
+  border-top-right-radius: 12px;
+}
+
+:deep(.el-scrollbar__wrap--hidden-default) {
+  border-radius: 0;
+}
+
+.is-disabled {
+  background-color: #f5f7fa;
+  color: #a8abb2;
+  cursor: not-allowed;
+  box-shadow: none !important;
+}
+
+:deep(.el-tag) {
+  border-color: transparent;
+}
+
+:deep(.custom-el-space) {
+  flex-grow: 1;
+}
+
+:deep(.custom-el-spaceno .el-space__item) {
+  width: initial;
+}
+
+:deep(.custom-el-space .el-space__item) {
+  width: 100%;
+}
+</style>

+ 1 - 0
src/components/SelectTableSelect/index.ts

@@ -0,0 +1 @@
+export { default } from './src/SelectTableSelect.vue'

+ 240 - 0
src/components/SelectTableSelect/src/SelectTableSelect.vue

@@ -0,0 +1,240 @@
+<script setup lang="ts">
+import { ref, watch } from 'vue'
+import IconDropDown from '@/components/IconDropDown'
+import VerrifyInformation from '@/components/VerrifyInformation'
+import SelectTable from '@/components/SelectTable'
+
+interface TypeItem {
+  placesType: ''
+  placesname: []
+  isshowVerfication: boolean
+}
+interface dateoptions {
+  value: string
+  label: string
+}
+interface Props {
+  AddDateType: TypeItem[]
+  ASPlaceholder: string
+  DateTypeoptions: dateoptions[]
+  Verification: string
+  selectedPartyTypeoptions: Array<string>
+}
+interface optionsItem {
+  value: string
+  label: string
+}
+const props = withDefaults(defineProps<Props>(), {})
+const AddType: any = ref([])
+const dataTypeoptions = ref<optionsItem[]>([])
+const typeSelectIndex = ref(-1)
+watch(
+  () => props.selectedPartyTypeoptions,
+  (newV) => {
+    let arr: any = []
+    if (newV.length == 0) {
+      arr = props.DateTypeoptions
+    } else {
+      props.DateTypeoptions.forEach((item: any) => {
+        let index = newV.findIndex((con: any) => {
+          return con == item.value
+        })
+        if (index < 0) {
+          arr.push(item)
+        }
+      })
+    }
+    dataTypeoptions.value = arr
+  },
+  {
+    immediate: true,
+    deep: true
+  }
+)
+
+watch(
+  () => props.AddDateType,
+  (val) => {
+    AddType.value = val
+  },
+  {
+    immediate: true,
+    deep: true
+  }
+)
+
+// 删除当前more type
+const deleteType = (i: any) => {
+  emit('delSelect', i, AddType.value[i].placesType)
+  AddType.value.splice(i, 1)
+}
+// 选中type改变
+const changeSelect = (val: any) => {
+  emit('changeAutoSelectAddType', typeSelectIndex.value, val)
+}
+// 选中name改变
+const emit = defineEmits(['changeAutoSelectAddType', 'delSelect', 'changeAutoSelect'])
+let AutoSelectObj: any = {}
+const changeAutoSelect = (val: any, value: any) => {
+  AutoSelectObj[val] = value.join()
+  emit('changeAutoSelect', AutoSelectObj)
+}
+const typeSelectFocus = (index: any, e: any) => {
+  typeSelectIndex.value = index
+}
+const typeSelectBlur = () => {
+  typeSelectIndex.value = -1
+  let arr: any = []
+  if (props.selectedPartyTypeoptions.length == 0) {
+    arr = props.DateTypeoptions
+  } else {
+    props.DateTypeoptions.forEach((item: any) => {
+      let index = props.selectedPartyTypeoptions.findIndex((con: any) => {
+        return con == item.value
+      })
+      if (index < 0) {
+        arr.push(item)
+      }
+    })
+  }
+  dataTypeoptions.value = arr
+}
+const typeSelectClick = (index: any, val: any) => {
+  if (AddType.value[index].placesType) {
+    let j = props.DateTypeoptions.findIndex((item: any) => {
+      return item.value == AddType.value[index].placesType
+    })
+    let i = dataTypeoptions.value.findIndex((item: any) => {
+      return item.value == AddType.value[index].placesType
+    })
+    if (i < 0) {
+      dataTypeoptions.value.push(props.DateTypeoptions[j])
+    }
+  } else {
+    let arr: any = []
+    if (props.selectedPartyTypeoptions.length == 0) {
+      arr = props.DateTypeoptions
+    } else {
+      props.DateTypeoptions.forEach((item: any) => {
+        let index = props.selectedPartyTypeoptions.findIndex((con: any) => {
+          return con == item.value
+        })
+        if (index < 0) {
+          arr.push(item)
+        }
+      })
+    }
+    dataTypeoptions.value = arr
+  }
+}
+
+const checkdestination = (row: any, index: any) => {
+  if (row) {
+    AddType.value[index].placesname = row
+    changeAutoSelect(AddType.value[index].placesType, AddType.value[index].placesname)
+  }
+}
+</script>
+<template>
+  <div class="AddType" v-for="(item, index) in AddType" :key="index">
+    <div>
+      <div class="Date_Title">
+        <div class="ETD_title">Places Type</div>
+        <span class="iconfont_icon" @click="deleteType(index)">
+          <svg class="iconfont icon_delete" aria-hidden="true">
+            <use xlink:href="#icon-icon_delete_b"></use>
+          </svg>
+        </span>
+      </div>
+      <el-select
+        v-model="AddType[index].placesType"
+        :suffix-icon="IconDropDown"
+        @blur="typeSelectBlur"
+        class="testname"
+        @focus="typeSelectFocus(index, $event)"
+        @click="typeSelectClick(index, $event)"
+        @change="changeSelect(AddType[index].placesType)"
+        placeholder="Please Select Party Type"
+      >
+        <el-option
+          v-for="item in dataTypeoptions"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value"
+        >
+        </el-option>
+      </el-select>
+    </div>
+    <div style="margin-top: 16px">
+      <div class="ETD_title">Places Details</div>
+      <SelectTable
+        :key-val="
+          AddType[index].placesType && AddType[index].placesType === 'Port of Loading'
+            ? 'uncode'
+            : 'city'
+        "
+        :disabled="AddType[index].placesType ? false : true"
+        :searchInput="AddType[index].placesname"
+        @check="(row) => checkdestination(row, index)"
+      />
+      <VerrifyInformation
+        :isshowVerfication="AddDateType[index]?.isshowVerfication"
+        :verification="props.Verification"
+      >
+      </VerrifyInformation>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.AddType {
+  background-color: var(--addparties-background-color);
+  margin: 0 16px 8px 16px;
+  padding: 8px;
+  border-radius: var(--border-radius-6);
+}
+
+.ETD_title {
+  font-size: var(--font-size-2);
+  color: var(--color-neutral-2);
+}
+
+.Date_Title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.icon_delete {
+  fill: var(--color-danger);
+  cursor: pointer;
+}
+
+.el-select-dropdown__item.is-selected {
+  div {
+    color: var(--badge__content--warning);
+  }
+
+  background-color: transparent;
+}
+
+.el-select-dropdown__item {
+  padding-left: 7.7px;
+  display: flex;
+  align-items: center;
+}
+
+.label {
+  margin-left: 8px;
+}
+
+.el-select-dropdown__item.is-hovering {
+  div {
+    color: var(--badge__content--warning);
+  }
+}
+
+.AlertInput :deep(.el-select__wrapper) {
+  box-shadow: 0 0 0 0.5px var(--color-danger);
+}
+</style>

+ 1 - 0
src/components/ShipmentStatus/index.ts

@@ -0,0 +1 @@
+export { default } from './src/ShipmentStatus.vue'

+ 205 - 0
src/components/ShipmentStatus/src/ShipmentStatus.vue

@@ -0,0 +1,205 @@
+<script setup lang="ts">
+import dayjs from 'dayjs'
+
+const props = defineProps({
+  data: Object
+})
+const simplexData: any = ref([])
+
+watch(
+  () => props.data,
+  (newVal) => {
+    if (newVal) {
+      simplexData.value = newVal
+    } else {
+      simplexData.value = []
+    }
+  },
+  {
+    immediate: true,
+    deep: true
+  }
+)
+
+// 中间点 每两个节点之间加上26px  上边距离28px 下边距离54px  如果没有中间点则高度为56px
+const getSimplexLineHeight = (index: number) => {
+  if (index === 0) {
+    return 56
+  } else {
+    return 28 + 56 + 26 * (index - 1)
+  }
+}
+const getDateHeight = (index: number) => {
+  return 42 + 26 * index
+}
+
+const formatDate = (date: string) => {
+  return date ? dayjs(date).format('MMM-DD-YYYY') : '--'
+}
+</script>
+
+<template>
+  <div class="simplex-content">
+    <div
+      class="detail-step-item"
+      :class="{
+        last: !stepItem.isArrival
+      }"
+      v-for="stepItem in simplexData"
+      :key="stepItem.index"
+    >
+      <div class="data">
+        <div class="left-step-icon">{{ stepItem.index }}</div>
+        <div class="right-info">
+          <div class="path">
+            <div class="label">{{ stepItem.label }}</div>
+            <div class="detail-path">{{ stepItem.path }}</div>
+          </div>
+          <div
+            class="transport-info"
+            :style="{ top: getDateHeight(dateIndex) + 'px' }"
+            v-for="(dateItem, dateIndex) in stepItem.children"
+            :key="dateIndex"
+          >
+            <div class="step-dot"></div>
+            <div class="label">{{ dateItem.label }}</div>
+            <div class="divider"></div>
+            <div class="date">{{ formatDate(dateItem.date) }}</div>
+          </div>
+        </div>
+      </div>
+      <div
+        class="line"
+        v-if="stepItem.label !== 'Place of Delivery'"
+        :style="{ height: getSimplexLineHeight(stepItem.children?.length || 0) + 'px' }"
+      ></div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+// 单式样式
+.simplex-content {
+  width: 100%;
+  padding: 8px 0 9px;
+}
+.detail-step-item {
+  & > .data {
+    display: flex;
+    position: relative;
+    height: 16px;
+
+    .left-step-icon {
+      width: 16px;
+      height: 16px;
+      margin-right: 8px;
+      border-radius: 50%;
+      background-color: var(--color-neutral-1);
+      font-size: 10px;
+      font-weight: 700;
+      text-align: center;
+      line-height: 16px;
+      color: #fff;
+    }
+    .right-info {
+      flex: 1;
+      position: relative;
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: flex-start;
+      gap: 8px;
+      margin-top: -8px;
+      .step-dot {
+        width: 8px;
+        height: 8px;
+        border-radius: 50%;
+        background-color: var(--color-neutral-1);
+      }
+      .path {
+        flex: 1;
+        display: flex;
+        align-items: center;
+        width: 100%;
+        border-radius: 6px;
+        .label,
+        .detail-path {
+          height: 32px;
+          padding: 0 8px;
+          line-height: 32px;
+        }
+        .label {
+          // width: 96px;
+          background-color: var(--color-neutral-1);
+          color: #fff;
+          font-weight: 500;
+          font-size: 12px;
+          border-radius: 3px 0 0 3px;
+        }
+        .detail-path {
+          flex: 1;
+          width: 252px;
+          background-color: #fff;
+          font-weight: 700;
+          color: var(--color-neutral-1);
+          border: 1px solid #bfc1c3;
+          border-left: 0;
+          border-radius: 0 3px 3px 0;
+        }
+      }
+      .transport-info {
+        position: absolute;
+        top: 20px;
+        left: -20px;
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        width: calc(100% + 20px);
+        .label {
+          font-weight: 700;
+        }
+        .divider {
+          flex: 1;
+          height: 0px;
+          margin-right: 8px;
+          border-top: 1px dashed var(--color-neutral-3);
+        }
+        .date {
+          font-size: 12px;
+        }
+      }
+    }
+  }
+  & > .line {
+    height: 72px;
+    margin-left: 7px;
+    border-left: 1px solid var(--color-neutral-1);
+  }
+  &.last {
+    & > .data {
+      .left-step-icon {
+        background-color: #ccd1db;
+      }
+      .right-info {
+        .step-dot {
+          background-color: #ccd1db;
+        }
+        .path {
+          .label {
+            background-color: #ccd1db;
+
+            font-weight: 600;
+            color: var(--color-neutral-1);
+          }
+          .detail-path {
+            border-color: #ccd1db;
+          }
+        }
+      }
+    }
+    & > .line {
+      border-left: 1px dashed var(--color-neutral-3);
+    }
+  }
+}
+</style>

+ 1 - 0
src/components/TransportMode/index.ts

@@ -0,0 +1 @@
+export { default } from './src/TransportMode.vue'

+ 299 - 0
src/components/TransportMode/src/TransportMode.vue

@@ -0,0 +1,299 @@
+<script setup lang="ts">
+import { ref, onMounted, onBeforeMount, watch, computed } from 'vue'
+import type { DropdownInstance } from 'element-plus'
+import emitter from '@/utils/bus'
+
+interface ListItem {
+  name: string
+  number: number
+  icon: string
+  checked: boolean
+}
+interface Props {
+  TransportListItem: ListItem[]
+}
+const props = withDefaults(defineProps<Props>(), {})
+const TransportList = ref(props.TransportListItem)
+watch(
+  () => props.TransportListItem,
+  (current) => {
+    TransportList.value = current
+  }
+)
+
+onMounted(() => {
+  emitter.on('clearTag', (tag: any) => {
+    if (tag.includes('Transport Mode')) {
+      clearList()
+    }
+  })
+})
+
+onBeforeMount(() => {
+  emitter.off('clearTag')
+})
+
+const checkAll = ref(false)
+const dropdown1 = ref<DropdownInstance>()
+let checkedCount: any[] = []
+const TotalAll = computed(() => {
+  var total_sum = 0
+  if (TransportList.value != undefined) {
+    TransportList.value.map((item) => {
+      total_sum += item.number
+    })
+  }
+  return total_sum
+})
+
+const handleCheckAllChange = (val: any) => {
+  checkedCount = []
+  TransportList.value.forEach((item: any) => {
+    if (val) {
+      item.checked = true
+      checkedCount.push(item.name)
+    } else {
+      item.checked = false
+      checkedCount = []
+    }
+  })
+}
+const handleCheckedTransportChange = (value: any, checked: any, index: any) => {
+  if (checked) {
+    checkedCount.push(value)
+    const map = new Map()
+    checkedCount.forEach((item) => map.set(item, true))
+    checkedCount = [...map.keys()]
+  } else {
+    if (checkedCount.length == 1) {
+      checkedCount.splice(0, 1)
+    } else {
+      checkedCount.splice(index, 1)
+    }
+  }
+  checkAll.value = checkedCount.length === TransportList.value.length
+}
+
+// 清除选中
+const clearList = () => {
+  checkAll.value = false
+  TransportList.value.forEach((item: any) => {
+    item.checked = false
+  })
+  changedata.value = ''
+  checkedCount = []
+  emit('clearTransportTags')
+}
+const emit = defineEmits(['TransportSearch', 'clearTransportTags'])
+const changedata = ref()
+//点击搜索
+const TransportSearch = (visible: any) => {
+  if (checkedCount.length == TransportList.value.length) {
+    changedata.value = 'All'
+  } else {
+    changedata.value = checkedCount.join(', ')
+  }
+  const TransportData = {
+    title: 'Transport Mode',
+    data: changedata.value
+  }
+  emit('TransportSearch', TransportData)
+  if (!dropdown1.value) return
+  if (visible) {
+    dropdown1.value.handleClose()
+  } else {
+    dropdown1.value.handleOpen()
+  }
+}
+</script>
+<template>
+  <div class="select">
+    <el-dropdown ref="dropdown1" trigger="click" :hide-on-click="false">
+      <div class="el-dropdown-link">
+        <div class="select_title">Transport Mode</div>
+        <span class="iconfont_icon">
+          <svg class="iconfont" aria-hidden="true">
+            <use xlink:href="#icon-icon_dropdown_b"></use>
+          </svg>
+        </span>
+      </div>
+      <template #dropdown>
+        <div class="dropdownwidth">
+          <div class="title">Transport Mode</div>
+          <el-dropdown-menu>
+            <el-dropdown-item>
+              <el-checkbox v-model="checkAll" class="checkbox" @change="handleCheckAllChange">
+                <div class="checkbox_title">
+                  <span class="iconfont_icon">
+                    <svg class="iconfont iconfont_select" aria-hidden="true">
+                      <use xlink:href="#icon-icon_all_b"></use>
+                    </svg>
+                  </span>
+                  Select All
+                </div>
+                <div class="checkbox_number">({{ TotalAll }})</div>
+              </el-checkbox>
+            </el-dropdown-item>
+            <el-divider></el-divider>
+            <el-dropdown-item v-for="(item, index) in TransportList" :key="index">
+              <el-checkbox
+                :value="item.name"
+                v-model="item.checked"
+                class="checkbox"
+                @change="handleCheckedTransportChange(item.name, item.checked, index)"
+              >
+                <div class="checkbox_title">
+                  <span class="iconfont_icon">
+                    <svg class="iconfont iconfont_select" aria-hidden="true">
+                      <use :xlink:href="item.icon"></use>
+                    </svg>
+                  </span>
+                  {{ item.name }}
+                </div>
+                <div class="checkbox_number">({{ item.number }})</div>
+              </el-checkbox>
+            </el-dropdown-item>
+            <div class="transport_bottom">
+              <div>
+                <el-button class="clear" type="default" @click="clearList">Reset</el-button>
+              </div>
+              <div>
+                <el-button class="search el-button--dark" @click="TransportSearch"
+                  >Search</el-button
+                >
+              </div>
+            </div>
+          </el-dropdown-menu>
+        </div>
+      </template>
+    </el-dropdown>
+  </div>
+</template>
+<style lang="scss" scoped>
+.iconfont_icon {
+  margin-right: 8px;
+}
+.iconfont_select {
+  width: 17px;
+  height: 17px;
+}
+.select {
+  width: 186px;
+  margin-left: 8px;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  border: 1px solid var(--color-border);
+  border-radius: var(--border-radius-6);
+}
+.select:hover {
+  border: 1px solid var(--color-theme);
+}
+.el-dropdown-link {
+  width: 186px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.select_title {
+  font-size: var(--font-size-3);
+  font-weight: 400;
+  margin-left: 8.53px;
+  color: var(--color-neutral-1);
+}
+.title {
+  font-weight: 700;
+  font-size: var(--font-size-5);
+  background-color: var(--color-header-bg);
+  height: 48px;
+  display: flex;
+  align-items: center;
+  padding-left: 16px;
+}
+.checkbox {
+  width: 216px;
+  font-weight: 400;
+  font-size: var(--font-size-3);
+  padding: 0 12px;
+  height: 40px;
+}
+:deep(.el-popper__arrow, .el-popper__arrow:before) {
+  height: 0;
+  width: 0;
+}
+:deep(.el-checkbox__label) {
+  width: 176px;
+  padding-left: 13px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.checkbox_title {
+  color: var(--color-neutral-1);
+}
+.checkbox_number {
+  color: var(--color-neutral-3);
+}
+.transport_bottom {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  height: 48px;
+  border-top: 1px solid var(--color-border);
+  margin-top: 5px;
+  font-weight: 400;
+  font-size: var(--font-size-3);
+}
+.clear {
+  width: 81px;
+  height: 32px;
+  margin-right: 7.82px;
+}
+.search {
+  width: 86px;
+  height: 32px;
+  margin-right: 16px;
+}
+.search:hover {
+  color: var(--color-theme);
+}
+:deep(.el-dropdown-menu__item:hover) {
+  background-color: var(--border-hover-color);
+  border-radius: var(--border-radius-6);
+  border-color: var(--border-hover-color);
+}
+:deep(.el-dropdown-menu__item) {
+  padding: 0;
+  margin: 10px 16px;
+}
+:deep(.el-dropdown-menu__item:not(.is-disabled):focus) {
+  background-color: var(--border-hover-color);
+  border-radius: var(--border-radius-6);
+  border-color: var(--border-hover-color);
+}
+.dropdownwidth {
+  width: 248px;
+}
+@media only screen and (min-width: 1280px) {
+  .el-dropdown-link,
+  .select {
+    width: 224px;
+  }
+  .dropdownwidth {
+    width: 248px;
+  }
+}
+@media only screen and (min-width: 1440px) {
+  .el-dropdown-link,
+  .select {
+    width: 336px;
+  }
+  .dropdownwidth {
+    width: 336px;
+  }
+}
+.el-divider--horizontal {
+  margin: 8px 0;
+  border-top-color: var(--color-border);
+}
+</style>

+ 1 - 0
src/components/VBox/index.ts

@@ -0,0 +1 @@
+export { default } from './src/VBox.vue'

+ 159 - 0
src/components/VBox/src/VBox.vue

@@ -0,0 +1,159 @@
+<script setup lang="ts">
+const props = withDefaults(
+  defineProps<{
+    id?: number
+    isSeeAll?: boolean
+    isDraggable?: boolean
+  }>(),
+  {
+    isSeeAll: true,
+    isDraggable: true
+  }
+)
+
+const isCollapse = defineModel<boolean>()
+const emits = defineEmits<{ collapse: [boolean]; draggable: [string, number] }>()
+const handleCollapse = (isCollapse: boolean) => {
+  emits('collapse', isCollapse)
+}
+
+const optionList = ref([
+  { id: 1, name: 'Move to Top', icon: 'icon_movetotop_b' },
+  {
+    id: 2,
+    name: 'Move Up',
+    icon: 'icon_moveup_b'
+  },
+  {
+    id: 3,
+    name: 'Move Down',
+    icon: 'icon_movedown_b'
+  },
+  {
+    id: 4,
+    name: 'Move to Bottom',
+    icon: 'icon_movetobottom__b'
+  }
+])
+
+const handleDraggable = (type: string) => {
+  if (!props.id) return
+  emits('draggable', type, props.id)
+  vBoxPopoverRef.value.hide()
+}
+
+const vBoxPopoverRef = ref()
+</script>
+
+<template>
+  <div class="v-box">
+    <div class="header">
+      <slot name="header">Title</slot>
+      <div class="option">
+        <SeeAllIcon
+          v-if="props.isSeeAll"
+          @update:modelValue="handleCollapse"
+          v-model="isCollapse"
+        />
+        <el-popover
+          ref="vBoxPopoverRef"
+          popper-class="v-box-options"
+          :width="172"
+          placement="bottom"
+          trigger="click"
+        >
+          <div class="options">
+            <div
+              class="move-item"
+              @click="handleDraggable(item.name)"
+              v-for="item in optionList"
+              :key="item.name"
+            >
+              <span class="font_family" :class="[`icon-${item.icon}`]"></span>
+              <span>{{ item.name }}</span>
+            </div>
+          </div>
+          <template #reference v-if="props.isDraggable">
+            <el-button type="text" class="sort handle-draggable">
+              <span class="font_family icon-icon_dragsort__b" style="font-size: 16px"></span>
+            </el-button>
+          </template>
+        </el-popover>
+      </div>
+    </div>
+    <div class="content">
+      <slot name="content"></slot>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.v-box {
+  border: 1px solid var(--color-border);
+  overflow: hidden;
+  border-radius: 12px;
+  & > .header {
+    position: relative;
+    padding: 0 16px;
+    height: 48px;
+    line-height: 48px;
+    background-color: var(--color-header-bg);
+    font-size: 18px;
+    font-weight: 700;
+    .option {
+      position: absolute;
+      right: 48px;
+      top: 50%;
+      transform: translateY(-50%);
+      display: flex;
+      align-items: center;
+    }
+    .sort {
+      position: absolute;
+      top: 50%;
+      right: -40px;
+      transform: translateY(-50%);
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      span.icon-icon_dragsort__b {
+        color: var(--color-neutral-1);
+      }
+      & .font_family {
+        &:active {
+          color: var(--color-theme);
+        }
+      }
+    }
+  }
+}
+</style>
+<style lang="scss">
+.el-popover.el-popper.v-box-options {
+  border-radius: 12px;
+}
+.v-box-options {
+  .options {
+    padding: 8px;
+    color: var(--color-neutral-1);
+    .move-item {
+      height: 40px;
+      line-height: 40px;
+
+      &:hover {
+        border-radius: 6px;
+        background-color: var(--color-btn-default-bg-hover);
+        span {
+          color: var(--color-theme);
+        }
+      }
+      .font_family {
+        margin-left: 8px;
+        margin-right: 10px;
+        font-size: 16px;
+        vertical-align: baseline;
+      }
+    }
+  }
+}
+</style>

+ 1 - 0
src/components/VBox_Dashboard/index.ts

@@ -0,0 +1 @@
+export { default } from './src/VBox_Dashboard.vue'

+ 169 - 0
src/components/VBox_Dashboard/src/VBox_Dashboard.vue

@@ -0,0 +1,169 @@
+<script setup lang="ts">
+import { ref } from 'vue'
+const props = withDefaults(
+  defineProps<{
+    id?: number
+  }>(),
+  {}
+)
+
+const emits = defineEmits<{ changeCancel: [boolean]; draggable: [string, number] }>()
+const changeCancel = (isShow: boolean) => {
+  emits('changeCancel', isShow)
+}
+
+const optionList = ref([
+  { id: 1, name: 'Move to Top', icon: 'icon_movetotop_b' },
+  {
+    id: 2,
+    name: 'Move Up',
+    icon: 'icon_moveup_b'
+  },
+  {
+    id: 3,
+    name: 'Move Down',
+    icon: 'icon_movedown_b'
+  },
+  {
+    id: 4,
+    name: 'Move to Bottom',
+    icon: 'icon_movetobottom__b'
+  }
+])
+
+const handleDraggable = (type: string) => {
+  if (!props.id) return
+  emits('draggable', type, props.id)
+  vBoxPopoverRef.value.hide()
+}
+
+const vBoxPopoverRef = ref()
+</script>
+
+<template>
+  <div class="v-box">
+    <div class="header">
+      <slot name="header">Title</slot>
+      <div class="option">
+        <!-- <el-popover
+          ref="vBoxPopoverRef"
+          popper-class="v-box-options"
+          :width="172"
+          placement="bottom"
+          trigger="click"
+        >
+          <div class="options">
+            <div
+              class="move-item"
+              @click="handleDraggable(item.name)"
+              v-for="item in optionList"
+              :key="item.name"
+            >
+              <span class="font_family" :class="[`icon-${item.icon}`]"></span>
+              <span>{{ item.name }}</span>
+            </div>
+          </div>
+          <template #reference> -->
+        <el-button type="text" class="sort handle-draggable">
+          <span class="iconfont_icon">
+            <svg class="iconfont" aria-hidden="true">
+              <use xlink:href="#icon-icon_dragsort__b"></use>
+            </svg>
+          </span>
+        </el-button>
+        <!-- </template>
+        </el-popover> -->
+      </div>
+      <div class="cancel" @click="changeCancel">
+        <span class="iconfont_icon">
+          <svg class="iconfont" aria-hidden="true">
+            <use xlink:href="#icon-icon_reject_b"></use>
+          </svg>
+        </span>
+      </div>
+    </div>
+    <div class="content">
+      <slot name="content"></slot>
+    </div>
+    <div class="content">
+      <slot name="content2"></slot>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.v-box {
+  border: 1px solid var(--color-border);
+  overflow: hidden;
+  border-radius: 12px;
+  & > .header {
+    position: relative;
+    padding: 0 16px 0 48px;
+    height: 48px;
+    line-height: 48px;
+    font-size: 18px;
+    border-bottom: 1px solid var(--color-border);
+    font-weight: 700;
+    .option {
+      position: absolute;
+      left: 0px;
+      top: 50%;
+      transform: translateY(-50%);
+      display: flex;
+      align-items: center;
+    }
+    .cancel {
+      position: absolute;
+      right: 26px;
+      cursor: pointer;
+      top: 0;
+    }
+    .sort {
+      position: absolute;
+      top: 50%;
+      right: -40px;
+      transform: translateY(-50%);
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      span.icon-icon_dragsort__b {
+        color: var(--color-neutral-1);
+      }
+      & .font_family {
+        &:active {
+          color: var(--color-theme);
+        }
+      }
+    }
+  }
+}
+</style>
+<style lang="scss">
+.el-popover.el-popper.v-box-options {
+  border-radius: 12px;
+}
+.v-box-options {
+  .options {
+    padding: 8px;
+    color: var(--color-neutral-1);
+    .move-item {
+      height: 40px;
+      line-height: 40px;
+
+      &:hover {
+        border-radius: 6px;
+        background-color: var(--color-btn-default-bg-hover);
+        span {
+          color: var(--color-theme);
+        }
+      }
+      .font_family {
+        margin-left: 8px;
+        margin-right: 10px;
+        font-size: 16px;
+        vertical-align: baseline;
+      }
+    }
+  }
+}
+</style>

+ 1 - 0
src/components/VBreadcrumd/index.ts

@@ -0,0 +1 @@
+export { default } from './src/VBreadcrumd.vue'

+ 38 - 0
src/components/VBreadcrumd/src/VBreadcrumd.vue

@@ -0,0 +1,38 @@
+<script setup lang="ts">
+import { useParentPathStore } from '@/stores/modules/parentPath'
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
+const parentPathStore = useParentPathStore()
+
+const handleGoBack = () => {
+  router.push({ path: parentPathStore.parentPathInfo?.fullPath })
+}
+</script>
+
+<template>
+  <div class="v-breadcrumd" v-if="parentPathStore.parentPathInfo?.name">
+    <span class="font_family icon-icon_back_b" @click="handleGoBack"></span>
+    <span style="color: var(--color-neutral-3)">{{ parentPathStore.parentPathInfo?.name }}</span>
+    <span class="interval">|</span>
+    <span style="font-weight: 700">Detail</span>
+  </div>
+  <div v-else></div>
+</template>
+
+<style lang="scss" scoped>
+.v-breadcrumd {
+  display: flex;
+  align-items: center;
+  gap: 4px;
+  .icon-icon_back_b {
+    font-size: 18px;
+    cursor: pointer;
+  }
+  .interval {
+    margin: 0 2px;
+    color: var(--color-neutral-3);
+    transform: rotate(20deg);
+  }
+}
+</style>

+ 0 - 0
src/components/VEmpty/index.ts


+ 49 - 0
src/components/VEmpty/src/VEmpty.vue

@@ -0,0 +1,49 @@
+<script setup lang="ts"></script>
+
+<template>
+  <div class="v-empty">
+    <div class="empty-img">
+      <img src="./images/default_image.png" alt="" />
+    </div>
+    <p class="title">Whoops, No matches</p>
+    <p class="light">We didn't find any search results,</p>
+    <p class="light">please try to adjust your search keywords.</p>
+    <div class="suggestion">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.v-empty {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  .empty-img {
+    margin-bottom: 16px;
+  }
+  .title {
+    margin-bottom: 8px;
+    font-weight: 600;
+    color: var(--color-neutral-2);
+  }
+  .light {
+    font-size: 12px;
+    line-height: 18px;
+    color: var(--color-neutral-3);
+  }
+  .suggestion {
+    margin-top: 16px;
+    padding: 8px;
+    font-size: 12px;
+    line-height: 18px;
+    border-radius: 6px;
+    text-align: left;
+    background-color: var(--color-table-header-bg);
+    :deep(p) {
+      margin: 0;
+      color: var(--color-neutral-3);
+    }
+  }
+}
+</style>

BIN
src/components/VEmpty/src/images/default_image.png


+ 1 - 0
src/components/VLoading/index.ts

@@ -0,0 +1 @@
+export { default } from './src/VLoading.vue'

+ 74 - 0
src/components/VLoading/src/VLoading.vue

@@ -0,0 +1,74 @@
+<script setup lang="ts">
+/**
+ *
+ * @param {string} target - 挂载的目标元素
+ * @param {boolean} loading - 是否显示loading
+ * @param {boolean} isLoadingBackground - 是否显示背景
+ */
+interface internalProps {
+  target?: string
+  loading: boolean
+  isLoadingBackground: boolean
+}
+
+const props = withDefaults(defineProps<internalProps>(), {
+  target: 'body',
+  isLoadingBackground: false
+})
+</script>
+<template>
+  <Teleport :to="props.target">
+    <div v-if="props.loading" class="v-loading-mask"
+      :style="{ background: props.isLoadingBackground ? 'none' : '#2B2F36' }">
+      <div class="v-loading-spinner">
+        <div>
+          <img class="circular" src="./images/icon_loading.png" alt="" />
+          <p class="loading-text">Loading...</p>
+        </div>
+      </div>
+    </div>
+  </Teleport>
+</template>
+
+<style scoped>
+.v-loading-mask {
+  position: absolute;
+  z-index: 2000;
+  margin: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  opacity: 0.7;
+}
+
+.v-loading-spinner {
+  top: 50%;
+  margin-top: -24px;
+  width: 100%;
+  text-align: center;
+  position: absolute;
+}
+
+.circular {
+  display: inline;
+  height: 48px;
+  width: 48px;
+  margin-bottom: 8px;
+  animation: loading-rotate 2s linear infinite;
+}
+
+.loading-text {
+  color: var(--color-neutral-3);
+}
+
+@keyframes loading-rotate {
+  0% {
+    transform: rotate(0deg);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
+</style>

BIN
src/components/VLoading/src/images/icon_loading.png


+ 1 - 0
src/components/VTag/index.ts

@@ -0,0 +1 @@
+export { default } from './src/VTag.vue'

+ 120 - 0
src/components/VTag/src/VTag.vue

@@ -0,0 +1,120 @@
+<script setup lang="ts">
+interface internalProps {
+  type?:
+    | 'Confirmed'
+    | 'Cancelled'
+    | 'Created'
+    | 'Booked'
+    | 'Cargo Received'
+    | 'Departure'
+    | 'Arrived'
+    | 'Completed'
+  large?: boolean
+}
+
+const mappingTable = new Map([
+  ['Confirmed', 'confirmed'],
+  ['Cancelled', 'cancelled'],
+  ['Created', 'created'],
+  ['Booked', 'booked'],
+  ['Cargo Received', 'cargo-received'],
+  ['Departure', 'departure'],
+  ['Arrived', 'arrived'],
+  ['Completed', 'completed']
+])
+defineProps<internalProps>()
+</script>
+
+<template>
+  <div :class="['v-tag', type && 'v-tag__' + mappingTable.get(type), large && 'large']">
+    <div class="dot"></div>
+    <slot />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.v-tag {
+  display: inline-flex;
+  justify-content: center;
+  cursor: default;
+  align-items: center;
+  padding: 4px 8px;
+  height: 22px;
+  line-height: 28px;
+  font-size: 12px;
+  border-radius: 12px;
+  background-color: #f7faff;
+  color: #4290ff;
+  &.large {
+    padding: 12px 12px;
+    height: 28px;
+    font-size: 14px;
+  }
+  .dot {
+    height: 5px;
+    width: 5px;
+    margin-right: 4px;
+    border-radius: 50%;
+    background-color: var(--color-tag-confirmed);
+  }
+  &.v-tag__confirmed {
+    background-color: var(--color-tag-confirmed-bg);
+    color: var(--color-tag-confirmed);
+    .dot {
+      background-color: var(--color-tag-confirmed);
+    }
+  }
+  &.v-tag__cancelled {
+    background-color: var(--color-tag-cancelled-bg);
+    color: var(--color-tag-cancelled);
+    .dot {
+      background-color: var(--color-tag-cancelled);
+    }
+  }
+  &.v-tag__created {
+    background-color: var(--color-tag-created-bg);
+    color: var(--color-tag-created);
+    .dot {
+      background-color: var(--color-tag-created);
+    }
+  }
+  &.v-tag__booked {
+    background-color: var(--color-tag-booked-bg);
+    color: var(--color-tag-booked);
+    .dot {
+      background-color: var(--color-tag-booked);
+    }
+  }
+  &.v-tag__cargo-received {
+    background-color: var(--color-tag-cargo-received-bg);
+    color: var(--color-tag-cargo-received);
+    .dot {
+      background-color: var(--color-tag-cargo-received);
+    }
+  }
+  &.v-tag__departure {
+    background-color: var(--color-tag-departure-bg);
+    color: var(--color-tag-departure);
+    .dot {
+      background-color: var(--color-tag-departure);
+    }
+  }
+  &.v-tag__arrived {
+    background-color: var(--color-tag-arrived-bg);
+    color: var(--color-tag-arrived);
+    .dot {
+      background-color: var(--color-tag-arrived);
+    }
+  }
+  &.v-tag__completed {
+    background-color: var(--color-tag-completed-bg);
+    color: var(--color-tag-completed);
+    .dot {
+      background-color: var(--color-tag-completed);
+    }
+  }
+  & + .v-tag {
+    margin-left: 8px;
+  }
+}
+</style>

+ 1 - 0
src/components/VerrifyInformation/index.ts

@@ -0,0 +1 @@
+export { default } from './src/VerrifyInformation.vue'

+ 18 - 0
src/components/VerrifyInformation/src/VerrifyInformation.vue

@@ -0,0 +1,18 @@
+<script setup lang="ts">
+const props = defineProps({
+  isshowVerfication: Boolean,
+  verification: String
+})
+</script>
+<template>
+  <div v-if="props.isshowVerfication" class="verification" id="verification">
+    {{ props.verification }}
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.verification {
+  color: var(--color-danger);
+  font-size: var(--font-size-2);
+}
+</style>

+ 7 - 0
src/components/icons/IconCommunity.vue

@@ -0,0 +1,7 @@
+<template>
+  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
+    <path
+      d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
+    />
+  </svg>
+</template>

+ 7 - 0
src/components/icons/IconDocumentation.vue

@@ -0,0 +1,7 @@
+<template>
+  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
+    <path
+      d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
+    />
+  </svg>
+</template>

+ 7 - 0
src/components/icons/IconEcosystem.vue

@@ -0,0 +1,7 @@
+<template>
+  <svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
+    <path
+      d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
+    />
+  </svg>
+</template>

+ 7 - 0
src/components/icons/IconSupport.vue

@@ -0,0 +1,7 @@
+<template>
+  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
+    <path
+      d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
+    />
+  </svg>
+</template>

+ 19 - 0
src/components/icons/IconTooling.vue

@@ -0,0 +1,19 @@
+<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
+<template>
+  <svg
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+    aria-hidden="true"
+    role="img"
+    class="iconify iconify--mdi"
+    width="24"
+    height="24"
+    preserveAspectRatio="xMidYMid meet"
+    viewBox="0 0 24 24"
+  >
+    <path
+      d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
+      fill="currentColor"
+    ></path>
+  </svg>
+</template>

+ 1 - 0
src/components/selectAutoSelect/index.ts

@@ -0,0 +1 @@
+export { default } from './src/selectAutoSelect.vue'

+ 286 - 0
src/components/selectAutoSelect/src/selectAutoSelect.vue

@@ -0,0 +1,286 @@
+<script setup lang="ts">
+import { ref, watch } from 'vue'
+import IconDropDown from '@/components/IconDropDown'
+import VerrifyInformation from '@/components/VerrifyInformation'
+interface TypeItem {
+  partyType: ''
+  partyname: []
+  isshowVerfication: boolean
+}
+interface ListItem {
+  value: string
+  label: string
+}
+interface dateoptions {
+  value: string
+  label: string
+}
+interface Props {
+  AddDateType: TypeItem[]
+  ASPlaceholder: string
+  DateTypeoptions: dateoptions[]
+  Verification: string
+  selectedPartyTypeoptions: Array<string>
+}
+interface optionsItem {
+  value: string
+  label: string
+}
+const list = ref<ListItem[]>([])
+const options = ref<ListItem[]>([])
+const loading = ref(false)
+const props = withDefaults(defineProps<Props>(), {})
+const AddType = ref(props.AddDateType)
+const value = ref()
+const dataTypeoptions = ref<optionsItem[]>([])
+const typeSelectIndex = ref(-1)
+watch(
+  () => props.selectedPartyTypeoptions,
+  (newV) => {
+    let arr: any = []
+    if (newV.length == 0) {
+      arr = props.DateTypeoptions
+    } else {
+      props.DateTypeoptions.forEach((item: any) => {
+        let index = newV.findIndex((con: any) => {
+          return con == item.value
+        })
+        if (index < 0) {
+          arr.push(item)
+        }
+      })
+    }
+    dataTypeoptions.value = arr
+  },
+  {
+    immediate: true,
+    deep: true
+  }
+)
+const str = ref()
+const InputAutoSelect = (val: any) => {
+  if (val.includes('Agent')) {
+    str.value = 'apex'
+  } else {
+    str.value = 'sales'
+  }
+}
+const remoteMethod = (query: string) => {
+  if (query) {
+    loading.value = true
+    setTimeout(() => {
+      $api
+        .getMoreFiltersData({
+          term: query,
+          type: str.value
+        })
+        .then((res: any) => {
+          if (res.code == 200) {
+            loading.value = false
+            list.value = res.data.map((item: any) => {
+              return { value: item, label: item }
+            })
+            options.value = list.value.filter((item) => {
+              return item.label.toLowerCase().includes(query.toLowerCase())
+            })
+          }
+        })
+    }, 200)
+  } else {
+    options.value = []
+  }
+}
+// 删除当前more type
+const deleteType = (i: any) => {
+  emit('delSelect', i, AddType.value[i].partyType)
+  AddType.value.splice(i, 1)
+}
+// 选中type改变
+const changeSelect = (val: any) => {
+  emit('changeAutoSelectAddType', typeSelectIndex.value, val)
+}
+// 选中name改变
+const emit = defineEmits(['changeAutoSelectAddType', 'delSelect', 'changeAutoSelect'])
+let AutoSelectObj: any = {}
+const changeAutoSelect = (val: any, value: any) => {
+  AutoSelectObj[val] = value.join()
+  emit('changeAutoSelect', AutoSelectObj)
+}
+// 清除警告样式
+const removeClass = (val: any, index: any) => {
+  const input_change = document.getElementsByClassName('input_change')
+  if (input_change.length && val.partyname.length != 0) {
+    if (input_change[index].classList.value.indexOf('AlertInput') != -1) {
+      input_change[index].classList.remove('AlertInput')
+    }
+  }
+}
+const typeSelectFocus = (index: any, e: any) => {
+  typeSelectIndex.value = index
+}
+const typeSelectBlur = () => {
+  typeSelectIndex.value = -1
+  let arr: any = []
+  if (props.selectedPartyTypeoptions.length == 0) {
+    arr = props.DateTypeoptions
+  } else {
+    props.DateTypeoptions.forEach((item: any) => {
+      let index = props.selectedPartyTypeoptions.findIndex((con: any) => {
+        return con == item.value
+      })
+      if (index < 0) {
+        arr.push(item)
+      }
+    })
+  }
+  dataTypeoptions.value = arr
+}
+const typeSelectClick = (index: any, val: any) => {
+  if (AddType.value[index].partyType) {
+    let j = props.DateTypeoptions.findIndex((item: any) => {
+      return item.value == AddType.value[index].partyType
+    })
+    let i = dataTypeoptions.value.findIndex((item: any) => {
+      return item.value == AddType.value[index].partyType
+    })
+    if (i < 0) {
+      dataTypeoptions.value.push(props.DateTypeoptions[j])
+    }
+  } else {
+    let arr: any = []
+    if (props.selectedPartyTypeoptions.length == 0) {
+      arr = props.DateTypeoptions
+    } else {
+      props.DateTypeoptions.forEach((item: any) => {
+        let index = props.selectedPartyTypeoptions.findIndex((con: any) => {
+          return con == item.value
+        })
+        if (index < 0) {
+          arr.push(item)
+        }
+      })
+    }
+    dataTypeoptions.value = arr
+  }
+}
+</script>
+<template>
+  <div class="AddType" v-for="(item, index) in AddType" :key="index">
+    <div>
+      <div class="Date_Title">
+        <div class="ETD_title">Party Type</div>
+        <span class="iconfont_icon" @click="deleteType(index)">
+          <svg class="iconfont icon_delete" aria-hidden="true">
+            <use xlink:href="#icon-icon_delete_b"></use>
+          </svg>
+        </span>
+      </div>
+      <el-select
+        v-model="AddType[index].partyType"
+        :suffix-icon="IconDropDown"
+        @blur="typeSelectBlur"
+        class="testname"
+        @focus="typeSelectFocus(index, $event)"
+        @click="typeSelectClick(index, $event)"
+        @change="changeSelect(AddType[index].partyType)"
+        placeholder="Please Select Party Type"
+      >
+        <el-option
+          v-for="item in dataTypeoptions"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value"
+        >
+        </el-option>
+      </el-select>
+    </div>
+    <div style="margin-top: 16px">
+      <div class="ETD_title">Party Details</div>
+      <el-select
+        v-model="AddType[index].partyname"
+        multiple
+        filterable
+        remote
+        class="input_change"
+        :reserve-keyword="false"
+        :placeholder="props.ASPlaceholder"
+        collapse-tags
+        @blur="removeClass(AddType[index], index)"
+        @input="InputAutoSelect(AddType[index].partyType)"
+        @change="changeAutoSelect(AddType[index].partyType, AddType[index].partyname)"
+        :disabled="AddType[index].partyType ? false : true"
+        collapse-tags-tooltip
+        :max-collapse-tags="3"
+        :remote-method="remoteMethod"
+        :loading="loading"
+      >
+        <el-option
+          v-for="item in options"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value"
+        >
+          <el-checkbox :checked="value?.includes(item.value)"></el-checkbox>
+          <div class="label">{{ item.value }}</div>
+        </el-option>
+      </el-select>
+      <VerrifyInformation
+        :isshowVerfication="AddDateType[index].isshowVerfication"
+        :verification="props.Verification"
+      ></VerrifyInformation>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.AddType {
+  background-color: var(--addparties-background-color);
+  margin: 0 16px 8px 16px;
+  padding: 8px;
+  border-radius: var(--border-radius-6);
+}
+
+.ETD_title {
+  font-size: var(--font-size-2);
+  color: var(--color-neutral-2);
+}
+
+.Date_Title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.icon_delete {
+  fill: var(--color-danger);
+  cursor: pointer;
+}
+
+.el-select-dropdown__item.is-selected {
+  div {
+    color: var(--badge__content--warning);
+  }
+
+  background-color: transparent;
+}
+
+.el-select-dropdown__item {
+  padding-left: 7.7px;
+  display: flex;
+  align-items: center;
+}
+
+.label {
+  margin-left: 8px;
+}
+
+.el-select-dropdown__item.is-hovering {
+  div {
+    color: var(--badge__content--warning);
+  }
+}
+
+.AlertInput :deep(.el-select__wrapper) {
+  box-shadow: 0 0 0 0.5px var(--color-danger);
+}
+</style>

+ 83 - 0
src/directive/VLoading.ts

@@ -0,0 +1,83 @@
+import { createApp, h } from 'vue'
+import Loading from '../components/VLoading'
+
+export const VLoading = {
+  mounted(el: any, binding: any) {
+    let options = {}
+    const target = el.getAttribute('target')
+    if (target) {
+      options = {
+        target: `${target}`
+      }
+    } else {
+      if (el.id) {
+        options = {
+          target: `#${el.id}`
+        }
+      } else {
+        el.id = `loading-target-${Math.random().toString(36).slice(2, 9)}`
+        options = {
+          target: `#${el.id}`
+        }
+      }
+    }
+    options = {
+      ...options,
+      isLoadingBackground: el.getAttribute('isLoadingBackground') || false
+    }
+    const app = createApp({
+      render() {
+        return h(Loading, { loading: binding.value, ...options })
+      }
+    })
+
+    const newDiv = document.createElement('div')
+    el.appendChild(newDiv) // 将 Loading 组件的根元素添加到目标元素中
+
+    const instance = app.mount(newDiv)
+
+    el.style.position = 'relative' // 确保父元素有相对定位
+    el.instance = instance
+    el.newDiv = newDiv // 保存对新 div 的引用
+    el.component = app // 保存 Vue 应用实例
+  },
+  updated(el: any, binding: any) {
+    if (binding.value !== binding.oldValue) {
+      // 卸载旧的组件
+      if (el.component) {
+        el.component.unmount()
+        el.component = null
+      }
+
+      // 移除旧的 div 元素
+      if (el.newDiv) {
+        el.removeChild(el.newDiv)
+        el.newDiv = null
+      }
+
+      // 创建新的 Vue 应用实例和 div 元素
+      const target = el.id || `loading-target-${Math.random().toString(36).substr(2, 9)}`
+      const app = createApp({
+        render() {
+          return h(Loading, { loading: binding.value, target: `#${target}` })
+        }
+      })
+
+      const newDiv = document.createElement('div')
+      el.appendChild(newDiv)
+      const instance = app.mount(newDiv)
+
+      el.instance = instance
+      el.newDiv = newDiv // 更新对新 div 的引用
+      el.component = app // 更新 Vue 应用实例
+    }
+  },
+  unmounted(el: any) {
+    if (el.newDiv) {
+      el.removeChild(el.newDiv) // 移除剩余的 div 元素
+    }
+    if (el.component) {
+      el.component.unmount() // 卸载 Vue 应用实例
+    }
+  }
+}

+ 67 - 0
src/hooks/calculatingHeight.ts

@@ -0,0 +1,67 @@
+/**
+ *
+ * @param parentElement 基准容器Ref
+ * @param fixedHeight 固定减去的值
+ * @param elementList 需要减去的可变的容器RefList
+ * @returns 高度值number
+ */
+export const useCalculatingHeight = (
+  parentElement: HTMLElement | null,
+  fixedHeight: number,
+  elementList: Ref<HTMLElement | null>[]
+) => {
+  const containerHeight = ref(0)
+  const calculatingHeight = () => {
+    if (parentElement) {
+      containerHeight.value = parentElement.offsetHeight - fixedHeight
+      elementList.forEach((item: any) => {
+        if (item.value) {
+          containerHeight.value -= item.value.offsetHeight || 0
+        }
+      })
+    }
+  }
+  // 创建 ResizeObserver 观察变化
+  const resizeObserver = new ResizeObserver(() => {
+    calculatingHeight()
+  })
+
+  // 开始观察
+  const startObserving = () => {
+    if (parentElement) {
+      resizeObserver.observe(parentElement)
+    }
+    elementList.forEach((item) => {
+      if (item.value) {
+        resizeObserver.observe(item.value)
+      }
+    })
+  }
+
+  // Vue 生命周期钩子
+  onMounted(() => {
+    nextTick(() => {
+      calculatingHeight()
+      startObserving()
+    })
+  })
+
+  // 停止观察
+  const stopObserving = () => {
+    resizeObserver.disconnect()
+  }
+
+  // Vue 生命周期钩子
+  onMounted(() => {
+    nextTick(() => {
+      calculatingHeight()
+      startObserving()
+    })
+  })
+
+  onBeforeUnmount(() => {
+    stopObserving()
+  })
+
+  return containerHeight
+}

+ 40 - 0
src/hooks/rowClickStyle.ts

@@ -0,0 +1,40 @@
+import { onMounted, onBeforeUnmount } from 'vue'
+
+export function useRowClickStyle(tableRef: any, rowClass: string = 'row--clicked') {
+  const handleMouseDown = (event: any) => {
+    const trElement = event.target.closest('tr')
+    if (trElement && trElement.hasAttribute('rowid')) {
+      const rowId = trElement.getAttribute('rowid')
+      const allRows = document.querySelectorAll(`tr[rowid="${rowId}"]`)
+      allRows.forEach((row) => {
+        row.classList.add(rowClass)
+      })
+
+      const handleMouseUp = () => {
+        allRows.forEach((row) => {
+          row.classList.remove(rowClass)
+        })
+        // 移除 mouseup 事件监听器
+        document.removeEventListener('mouseup', handleMouseUp)
+      }
+
+      // 监听 mouseup 事件,抬起鼠标时移除类名
+      document.addEventListener('mouseup', handleMouseUp)
+    }
+  }
+
+  onMounted(() => {
+    const gridElement = tableRef.value?.$el
+    if (gridElement) {
+      // 为表格添加 mousedown 事件监听器
+      gridElement.addEventListener('mousedown', handleMouseDown)
+    }
+  })
+
+  onBeforeUnmount(() => {
+    const gridElement = tableRef.value?.$el
+    if (gridElement) {
+      gridElement.removeEventListener('mousedown', handleMouseDown)
+    }
+  })
+}

+ 1 - 0
src/icons/icon_bold_b.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1725959674170" class="icon" viewBox="0 0 1088 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7008" xmlns:xlink="http://www.w3.org/1999/xlink" width="212.5" height="200"><path d="M536.832 32H265.792C229.312 32 199.68 61.568 199.68 98.048V925.44c0 36.736 29.76 66.56 66.496 66.56h378.624a280.064 280.064 0 0 0 104.768-539.968A263.872 263.872 0 0 0 536.832 32zM327.68 431.744V160h209.088a135.872 135.872 0 1 1 0 271.744H327.744z m0 432.192V559.808h317.12a152.064 152.064 0 1 1 0 304.128H327.744z" p-id="7009"></path></svg>

+ 3 - 0
src/icons/icon_date_b.svg

@@ -0,0 +1,3 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.17346 3.49834V4.60463H6.37346V3.49834H9.45935V4.60463H10.6594V3.49834H13.8664V5.8767H2.26641V3.49834H5.17346ZM5.17346 2.29834H2.26641H1.06641V3.49834V13.2775V14.4775H2.26641H13.8664H15.0664V13.2775V3.49834V2.29834H13.8664H10.6594V1.52246H9.45935V2.29834H6.37346V1.52246H5.17346V2.29834ZM2.26641 7.0767V13.2775H13.8664V7.0767H2.26641Z" fill="#2B2F36"/>
+</svg>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 4 - 0
src/icons/icon_logo.svg


+ 1 - 0
src/icons/icon_quotes_b.svg

@@ -0,0 +1 @@
+<svg t="1725953102375" class="icon" viewBox="0 0 1088 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6853" width="200" height="200"><path d="M149.504 503.04l181.248-278.4a38.4 38.4 0 1 1 64.384 41.92l-97.152 149.12a208.64 208.64 0 1 1-153.6 99.264 38.4 38.4 0 0 1 5.12-11.904z m478.848 0l181.248-278.4a38.4 38.4 0 1 1 64.384 41.92l-97.152 149.12a208.64 208.64 0 1 1-153.6 99.264 38.336 38.336 0 0 1 5.12-11.904z" p-id="6854"></path></svg>

+ 1 - 0
src/icons/icon_redo_b.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1725960121756" class="icon" viewBox="0 0 1088 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7929" xmlns:xlink="http://www.w3.org/1999/xlink" width="212.5" height="200"><path d="M972.608 422.528a32 32 0 0 1 0 50.496l-200.64 156.224a32 32 0 0 1-51.648-25.28V486.144H494.72a278.336 278.336 0 0 0-275.648 240c-2.88 20.992-19.84 38.272-40.96 38.272-21.248 0-38.656-17.28-36.416-38.4a355.136 355.136 0 0 1 353.024-316.672h225.536v-117.76a32 32 0 0 1 51.648-25.28l200.64 156.16z" p-id="7930"></path></svg>

+ 1 - 0
src/icons/icon_revoke__b.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1725960115265" class="icon" viewBox="0 0 1088 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7774" xmlns:xlink="http://www.w3.org/1999/xlink" width="212.5" height="200"><path d="M152.064 422.528a32 32 0 0 0 0 50.496L352.64 629.248a32 32 0 0 0 51.712-25.28V486.144h225.472a278.336 278.336 0 0 1 275.648 240c2.88 20.992 19.84 38.272 41.024 38.272s38.592-17.28 36.352-38.4a355.136 355.136 0 0 0-353.024-316.672H404.48v-117.76a32 32 0 0 0-51.712-25.28L152.064 422.4z" p-id="7775"></path></svg>

+ 1 - 0
src/icons/icon_underline_b.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1725959944625" class="icon" viewBox="0 0 1088 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7315" xmlns:xlink="http://www.w3.org/1999/xlink" width="212.5" height="200"><path d="M251.392 22.016a38.4 38.4 0 0 0-38.4 38.4V448.64a349.376 349.376 0 1 0 698.752 0V60.416a38.4 38.4 0 1 0-76.8 0V448.64a272.576 272.576 0 1 1-545.152 0V60.416a38.4 38.4 0 0 0-38.4-38.4z m-107.072 941.44a38.4 38.4 0 0 0 38.4 38.4h759.232a38.4 38.4 0 0 0 0-76.8H182.72a38.4 38.4 0 0 0-38.4 38.4z" p-id="7316"></path></svg>

+ 44 - 0
src/main.ts

@@ -0,0 +1,44 @@
+import './assets/main.css'
+import './styles/index.scss'
+import './styles/icons/iconfont.js'
+import VXETable from 'vxe-table'
+import 'vxe-table/lib/style.css'
+import enUS from 'vxe-table/lib/locale/lang/en-US'
+import VxeUI from 'vxe-pc-ui'
+import 'element-plus/dist/index.css'
+import 'vxe-pc-ui/lib/style.css'
+import Antd from 'ant-design-vue'
+import 'ant-design-vue/dist/reset.css'
+import * as ElementPlusIconsVue from '@element-plus/icons-vue'
+import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'
+import ExcelJS from 'exceljs'
+import { VLoading } from './directive/VLoading'
+
+import { createApp } from 'vue'
+import { createPinia } from 'pinia'
+
+import App from './App.vue'
+import router from './router'
+
+const app = createApp(App)
+
+for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+  app.component(key, component)
+}
+// 让VxeTable支持导出Excel
+VXETable.use(VXETablePluginExportXLSX, {
+  ExcelJS
+})
+VXETable.setI18n('en-US', enUS)
+VXETable.setLanguage('en-US')
+
+app.use(createPinia())
+app.use(VXETable)
+app.use(VxeUI)
+app.use(router)
+app.use(Antd)
+
+// 注册全局指令
+app.directive('vloading', VLoading)
+
+app.mount('#app')

+ 80 - 0
src/router/index.ts

@@ -0,0 +1,80 @@
+import { createRouter, createWebHistory } from 'vue-router'
+import { useParentPathStore } from '@/stores/modules/parentPath'
+
+const router = createRouter({
+  history: createWebHistory(import.meta.env.BASE_URL),
+  routes: [
+    {
+      path: '/',
+      name: 'Home',
+      redirect: '/booking',
+      component: () => import('../views/Layout'),
+      children: [
+        {
+          path: '/dashboard',
+          name: 'Dashboard',
+          component: () => import('../views/Dashboard')
+        },
+        {
+          path: '/booking',
+          name: 'Booking',
+          component: () => import('../views/Booking')
+        },
+        {
+          path: '/booking/detail',
+          name: 'Booking Detail',
+          component: () => import('../views/Booking/src/components/BookingDetail'),
+          meta: {
+            parentPath: '/booking'
+          }
+        },
+        {
+          path: '/tracking',
+          name: 'Tracking',
+          component: () => import('../views/Tracking')
+        },
+        {
+          path: '/tracking/detail',
+          name: 'Tracking Detail',
+          component: () => import('../views/Tracking/src/components/TrackingDetail')
+        },
+        {
+          path: '/public-tracking',
+          name: 'Public Tracking',
+          component: () => import('../views/Tracking/src/components/PublicTracking')
+        },
+        {
+          path: '/public-tracking/detail',
+          name: 'Public Tracking Detail',
+          component: () =>
+            import(
+              '../views/Tracking/src/components/PublicTracking/src/components/PublicTrackingDetail.vue'
+            )
+        },
+        {
+          path: '/login',
+          name: 'Login',
+          component: () => import('../views/Login')
+        },
+        {
+          path: '/Operationlog',
+          name: 'Operationlog',
+          component: () => import('../views/OperationLog')
+        }
+      ]
+    }
+  ]
+})
+
+// * 路由拦截 beforeEach
+router.beforeEach(async (to, from, next) => {
+  const parentPathStore = useParentPathStore()
+  if (to.path.includes('/detail')) {
+    parentPathStore.setParentPath(from)
+  } else {
+    parentPathStore.clearParentPath()
+  }
+  next()
+})
+
+export default router

+ 1 - 0
src/shims-vue.d.ts

@@ -0,0 +1 @@
+declare module '@wangeditor/editor-for-vue'

+ 4 - 0
src/stores/index.ts

@@ -0,0 +1,4 @@
+import { createPinia } from 'pinia'
+const store = createPinia()
+
+export default store

+ 8 - 0
src/stores/modules/BookingData.ts

@@ -0,0 +1,8 @@
+import {ref } from 'vue'
+import { defineStore } from 'pinia'
+
+export const useBookingStore = defineStore('BookingData', () => {
+  const TransportData = ref()
+
+  return {TransportData}
+})

+ 28 - 0
src/stores/modules/parentPath.ts

@@ -0,0 +1,28 @@
+import { defineStore } from 'pinia'
+interface ParentPath {
+  parentPathInfo: {
+    fullPath?: string
+    name?: string
+  }
+}
+
+export const useParentPathStore = defineStore('parentPath', {
+  state: (): ParentPath => ({
+    parentPathInfo: JSON.parse(localStorage.getItem('parentPathInfo') as string) || {}
+  }),
+  getters: {},
+  actions: {
+    setParentPath(route: any) {
+      const pathInfo = {
+        name: route.name,
+        fullPath: route.fullPath
+      }
+      localStorage.setItem('parentPath', JSON.stringify(pathInfo))
+      this.parentPathInfo = pathInfo
+    },
+    clearParentPath() {
+      localStorage.removeItem('parentPath')
+      this.parentPathInfo = {}
+    }
+  }
+})

+ 66 - 0
src/styles/Antdui.scss

@@ -0,0 +1,66 @@
+:where(.css-dev-only-do-not-override-19iuou).ant-picker-range {
+  height: 40px;
+  border: 1px solid var(--color-border-1);
+}
+:where(.css-dev-only-do-not-override-19iuou).ant-picker:hover, :where(.css-dev-only-do-not-override-19iuou).ant-picker-focused {
+  border-color: var(--color-theme);
+  box-shadow: none;
+}
+.ant-picker-active-bar {
+  display: none;
+}
+:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown-range {
+  z-index: 9999;
+}
+:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner::before {
+  border: none;
+}
+:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-selected .ant-picker-cell-inner, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-start .ant-picker-cell-inner, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-end .ant-picker-cell-inner {
+  background-color: var(--color-theme);
+  color: #FFFFFF;
+}
+:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-in-range::before {
+  background-color: var(--color-orange-6);
+}
+:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-start:not(.ant-picker-cell-range-start-single)::before, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-end:not(.ant-picker-cell-range-end-single)::before {
+  background-color: var(--color-orange-6);
+}
+:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-in-range {
+  color: var(--color-theme);
+}
+.ant-picker-cell:hover:not(.ant-picker-cell-in-view).ant-picker-cell-inner,
+
+  .ant-picker-cell:hover:not(.ant-picker-cell-selected):not(.ant-picker-cell-range-start)
+
+    :not(.ant-picker-cell-range-end):not(.ant-picker-cell-range-hover-start):not(.ant-picker-cell-range-hover-end) {
+      background-color: var(--color-orange-6) !important;
+      color: var(--color-theme);
+  }
+  :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-date-panel .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-start .ant-picker-cell-inner::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-date-panel .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-end .ant-picker-cell-inner::after {
+    background-color: var(--color-orange-6);
+  }
+  :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover::before, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-start.ant-picker-cell-range-hover::before, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-end.ant-picker-cell-range-hover::before, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-start:not(.ant-picker-cell-range-start-single).ant-picker-cell-range-hover-start::before, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-end:not(.ant-picker-cell-range-end-single).ant-picker-cell-range-hover-end::before, .ant-picker-panel>:not(.ant-picker-date-panel) :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-start::before, .ant-picker-panel>:not(.ant-picker-date-panel) :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-end::before {
+    background-color: var(--color-orange-6);
+  }
+  :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:not(.ant-picker-cell-in-range):not(.ant-picker-cell-range-start):not(.ant-picker-cell-range-end)::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end:not(.ant-picker-cell-in-range):not(.ant-picker-cell-range-start):not(.ant-picker-cell-range-end)::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start.ant-picker-cell-range-start-single::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start.ant-picker-cell-range-start.ant-picker-cell-range-end.ant-picker-cell-range-end-near-hover::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end.ant-picker-cell-range-start.ant-picker-cell-range-end.ant-picker-cell-range-start-near-hover::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end.ant-picker-cell-range-end-single::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover:not(.ant-picker-cell-in-range)::after {
+    border-top: none;
+    border-bottom: none;
+  }
+  tr>:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover:first-child::after, tr>:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end:first-child::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-start.ant-picker-cell-range-hover-edge-start.ant-picker-cell-range-hover-edge-start-near-range::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-edge-start:not(.ant-picker-cell-range-hover-edge-start-near-range)::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start::after {
+    border-inline-start: none;
+  }
+  tr>:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover:last-child::after, tr>:where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-end.ant-picker-cell-range-hover-edge-end.ant-picker-cell-range-hover-edge-end-near-range::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-edge-end:not(.ant-picker-cell-range-hover-edge-end-near-range)::after, :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end::after {
+    border-inline-end: none;
+  }
+  :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-header-view button:hover {
+    color: var(--color-theme);
+  }
+  :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-panel-container .ant-picker-panels .ant-picker-panel {
+    border-left: 1px solid var(--color-border);
+  }
+  .ant-picker-footer {
+    border-top: 1px solid var(--color-border);
+  }
+  :where(.css-dev-only-do-not-override-19iuou).ant-picker-dropdown .ant-picker-panel {
+    border: none;
+  }

+ 526 - 0
src/styles/elementui.scss

@@ -0,0 +1,526 @@
+// button
+.el-button.el-button--noborder {
+  border: none;
+  background-color: var(--color-white);
+  span {
+    color: var(--color-theme);
+  }
+  &:hover {
+    border-color: var(--color-btn-default-bg-hover);
+    background-color: var(--color-btn-default-bg-hover);
+    fill: var(--color-theme);
+    span {
+      color: var(--color-theme);
+    }
+  }
+}
+
+button.el-button.el-button--text {
+  height: 24px;
+  padding: 4px 8px;
+  border: none;
+  background-color: transparent;
+  span {
+    color: var(--color-theme);
+  }
+  &:hover {
+    background-color: var(--color-btn-default-bg-hover);
+    color: var(--color-theme);
+  }
+}
+
+.el-button.el-button--default {
+  background-color: var(--color-white);
+  color: var(--color-neutral-1);
+  border: 1px solid var(--color-border);
+  &:hover {
+    border: 1px solid var(--color-btn-default-bg-hover);
+    background-color: var(--color-btn-default-bg-hover);
+    fill: var(--color-theme);
+    span {
+      color: var(--color-theme);
+    }
+  }
+  &:focus {
+    border: 1px solid var(--color-btn-default-bg-hover);
+    background-color: var(--color-btn-default-bg-hover);
+    fill: var(--color-theme);
+    span {
+      color: var(--color-theme);
+    }
+  }
+}
+
+.el-button.el-button--main.is-plain {
+  background-color: var(--color-white);
+  border: 1px solid var(--color-border);
+  span {
+    color: var(--color-theme);
+  }
+  &:hover {
+    border: 1px solid var(--color-btn-main-plain-bg-hover);
+    background-color: var(--color-btn-main-plain-bg-hover);
+    color: var(--color-theme);
+    fill: var(--color-theme);
+  }
+}
+
+.el-button.el-button--main {
+  border: none;
+  background-color: var(--color-theme);
+  span {
+    color: var(--color-white);
+  }
+  &:hover {
+    background-color: var(--color-btn-main-bg-hover);
+    color: var(--color-white);
+    fill: var(--color-white);
+  }
+}
+
+.el-button.el-button--success {
+  border: none;
+  background-color: var(--color-success);
+  span {
+    color: var(--color-white);
+  }
+  &:hover {
+    background-color: var(--color-btn-success-bg-hover);
+    color: var(--color-white);
+    fill: var(--color-white);
+  }
+}
+
+.el-button.el-button--warning {
+  border: none;
+  background-color: var(--color-btn-warning-bg);
+  span {
+    color: var(--color-white);
+  }
+  &:hover {
+    background-color: var(--color-btn-warning-bg-hover);
+    color: var(--color-white);
+    fill: var(--color-white);
+  }
+}
+
+.el-button.el-button--danger {
+  border: none;
+  background-color: var(--color-danger);
+  span {
+    color: var(--color-white);
+  }
+  &:hover {
+    background-color: var(--color-btn-danger-bg-hover);
+    color: var(--color-white);
+    fill: var(--color-white);
+  }
+}
+
+.el-button.el-button--grey {
+  border: none;
+  background-color: var(--color-grey);
+  color: var(--color-accent-1);
+  &:hover {
+    background-color: var(--color-btn-default-bg-hover);
+    fill: var(--color-theme);
+    span {
+      color: var(--color-theme);
+    }
+  }
+}
+
+.el-button.el-button--blue {
+  border: none;
+  padding: 0 4px;
+  background-color: #f6f6fe;
+  color: var(--color-accent-1);
+  &:hover {
+    background-color: var(--color-btn-default-bg-hover);
+    fill: var(--color-theme);
+    span {
+      color: var(--color-theme);
+    }
+  }
+}
+
+// 纯图标
+button.el-button.el-button--icon {
+  height: auto;
+  padding: 4px;
+  border: none;
+  background-color: #f6f6fe;
+  &:hover {
+    background-color: #f6f6fe;
+  }
+}
+// 初始为黑色
+.el-button.el-button--dark {
+  background-color: var(--color-btn-default-dark-bg);
+  fill: var(--color-white);
+  border: none;
+  span {
+    color: var(--color-white);
+  }
+  &:hover {
+    background-color: var(--color-btn-default-dark-bg);
+    fill: var(--color-btn-default-dark-hover);
+    span {
+      color: var(--color-btn-default-dark-hover) !important;
+    }
+  }
+}
+
+button.el-button {
+  border-radius: 6px;
+}
+
+// pagination
+ul.el-pager li.is-active {
+  font-weight: 400;
+}
+div.el-pagination.is-background .el-pager li.is-active {
+  border: none;
+  background-color: var(--color-theme);
+  color: var(--color-white);
+}
+.el-pagination.is-background .el-pager li.number,
+.el-pagination.is-background .el-pager li.more,
+.el-pagination.is-background button.btn-next,
+.el-pagination.is-background button.btn-prev {
+  border-radius: 3px;
+  background-color: transparent;
+  border: 1px solid var(--color-border);
+}
+.el-pagination.is-background button.btn-next:disabled,
+.el-pagination.is-background button.btn-prev:disabled {
+  color: var(--color-neutral-1);
+  background-color: transparent;
+}
+
+ul.el-pager li:hover {
+  color: var(--color-theme);
+}
+
+// dialog
+div.el-dialog {
+  padding: 0 0 8px;
+  border-radius: 12px;
+  overflow: hidden;
+}
+header.el-dialog__header {
+  padding: 12px 16px;
+  height: 48px;
+  font-weight: 700;
+  background-color: var(--color-dialog-header-bg);
+}
+footer.el-dialog__footer {
+  padding-right: 16px;
+  padding-top: 8px;
+  border-top: 1px solid var(--color-border);
+}
+div.el-dialog__body {
+  padding: 16px;
+}
+
+// radio
+label.el-radio {
+  &.is-checked .el-radio__inner {
+    background-color: var(--color-theme);
+    border-color: var(--color-theme);
+  }
+  .el-radio__inner {
+    height: 16px;
+    width: 16px;
+    &::after {
+      height: 8px;
+      width: 8px;
+    }
+  }
+}
+
+// drawer抽屉
+div.el-drawer {
+  .el-drawer__header {
+    height: 64px;
+    padding: 16px;
+    margin-bottom: 0;
+    background-color: var(--color-table-header-bg);
+    & > span {
+      font-weight: 700;
+      font-size: 24px;
+    }
+  }
+  .el-drawer__body {
+    padding: 16px;
+  }
+}
+
+div .el-input__inner {
+  color: var(--color-neutral-1);
+  font-size: var(--font-size-3);
+}
+input.el-input__inner::placeholder {
+  color: var(--color-neutral-3);
+  font-size: var(--font-size-3);
+}
+div .el-select__placeholder.is-transparent {
+  span {
+    color: var(--color-neutral-3) !important;
+    font-size: var(--font-size-3);
+  }
+}
+div.el-input__wrapper {
+  box-shadow: 0 0 0 1px var(--color-border) inset;
+  padding-left: 8px;
+}
+div.el-input div.el-input__wrapper.is-focus {
+  box-shadow: 0 0 0 1px var(--color-theme) inset;
+  background-color: #ffffff !important;
+}
+div.el-input__wrapper:hover {
+  box-shadow: 0 0 0 1px var(--color-theme) inset;
+}
+// div .el-button {
+//   background-color: var(--color-btn-default-dark-bg);
+//   font-weight: 400;
+//   border-radius: var(--border-radius-6);
+//   border: none;
+//   span {
+//     color: white;
+//   }
+// }
+// div .el-button:hover {
+//   background-color: var(--color-btn-default-dark-bg);
+//   color: var(--color-btn-default-dark-hover);
+//   border-radius: var(--border-radius-6);
+// }
+div.el-dropdown-link:focus-visible {
+  outline: unset;
+}
+div .el-dropdown__popper .el-dropdown__list {
+  user-select: none;
+}
+div .el-checkbox__inner:hover {
+  border-color: var(--color-border);
+}
+div .el-checkbox__input.is-checked .el-checkbox__inner {
+  background-color: var(--color-theme);
+  border-color: var(--color-theme);
+}
+div .el-popper__arrow,
+div .el-popper__arrow:before {
+  height: 0;
+  width: 0;
+}
+div .el-popper[data-popper-placement^='bottom'] > .el-popper__arrow {
+  top: 0;
+}
+div .el-dropdown-menu__item {
+  border: 1px solid var(--color-border);
+  border-radius: var(--border-radius-6);
+}
+div .el-dropdown__popper.el-popper,
+.el-dropdown__popper.el-popper .el-popper__arrow:before {
+  border-radius: var(--border-radius-12);
+}
+div .el-scrollbar__wrap--hidden-default {
+  border-radius: var(--border-radius-12);
+}
+div .el-popper[data-popper-placement^='top'] .el-popper__arrow:before {
+  border: 0;
+  background: transparent;
+}
+div .el-popper[data-popper-placement^='bottom'] .el-popper__arrow:before {
+  border: 0;
+  background: transparent;
+}
+div .el-popover.el-popper {
+  padding: 0;
+}
+.el-popper.is-dark {
+  span {
+    color: #fff;
+  }
+}
+div .el-collapse-item__arrow,
+.el-tabs__nav {
+  transform: rotate(90deg);
+}
+div .el-collapse-item__arrow.is-active {
+  transform: rotate(-90deg);
+}
+div .el-collapse-item__content {
+  padding-bottom: 0;
+}
+.el-select__placeholder.is-transparent {
+  span {
+    color: var(--color-neutral-3);
+  }
+}
+div .el-select__wrapper {
+  box-shadow: 0 0 0 1px var(--color-border);
+}
+div .el-select__wrapper.is-focused {
+  box-shadow: 0 0 0 1px var(--color-theme);
+}
+div .el-select-dropdown__item.is-selected {
+  background-color: var(--border-hover-color);
+  span {
+    color: var(--color-theme);
+  }
+}
+div .el-select-dropdown__item.is-hovering {
+  background-color: var(--border-hover-color);
+}
+.el-select-dropdown__item {
+  border-radius: var(--border-radius-6);
+  margin: 0 8px;
+}
+
+div .el-badge__content--warning {
+  background-color: var(--badge__content--warning);
+  border-radius: 50%;
+  width: 20px;
+  height: 20px;
+  color: #ffffff;
+}
+div .el-badge {
+  margin: 8px 0 0 8px;
+}
+
+div .el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell {
+  background-color: var(--color-table-header-bg);
+}
+div .el-range-editor.is-active,
+.el-range-editor.is-active:hover,
+.el-date-editor.el-input__wrapper:hover,
+.el-date-editor.el-input__wrapper:hover {
+  box-shadow: 0 0 0 1px var(--color-theme) !important;
+  border-color: var(--color-theme);
+}
+div .el-date-table td.today .el-date-table-cell__text,
+.el-date-table td.available:hover {
+  color: var(--color-theme);
+}
+div .el-date-table td.in-range .el-date-table-cell {
+  background-color: var(--color-orange-6) !important;
+  color: var(--color-theme);
+}
+div .el-date-table td.end-date .el-date-table-cell__text,
+.el-date-table td.start-date .el-date-table-cell__text {
+  background-color: var(--color-theme) !important;
+  color: #ffffff;
+}
+div .el-date-table td.available:hover {
+  color: var(--color-theme);
+}
+div .el-date-editor .el-range-input,
+div .el-date-editor .el-range-separator {
+  color: var(--color-btn-default-dark-bg);
+  font-size: var(--font-size-3);
+}
+div .el-range-editor.el-input__wrapper {
+  height: 40px;
+}
+div .el-select__wrapper.is-hovering:not(.is-focused) {
+  box-shadow: 0 0 0 1px var(--color-theme);
+}
+div .el-tag .el-tag__close:hover {
+  background-color: transparent;
+}
+div .el-tag.el-tag--info {
+  background-color: var(--tag-info-bg-color);
+  span {
+    color: var(--tag-info-text-color);
+  }
+}
+div .el-tag .el-tag__close {
+  svg {
+    color: var(--tag-info-text-color);
+  }
+}
+div .el-select-dropdown.is-multiple .el-select-dropdown__item.is-selected:after {
+  width: 0;
+  height: 0;
+}
+div .el-select__wrapper.is-disabled,
+.el-select__wrapper.is-disabled:hover {
+  box-shadow: none !important;
+}
+div .scoreDialog header.el-dialog__header {
+  background: linear-gradient(
+    251deg,
+    rgba(255, 255, 255, 0.3),
+    rgba(255, 244, 235, 0.5) 22.66%,
+    rgba(240, 243, 255, 0.5) 44.57%,
+    rgba(224, 247, 249, 0.6) 80.46%,
+    rgba(255, 255, 255, 0.3)
+  );
+}
+
+div .el-textarea__inner:hover {
+  box-shadow: 0 0 0 1px var(--color-theme);
+}
+div .el-textarea__inner:focus {
+  box-shadow: 0 0 0 1px var(--color-theme);
+}
+div .el-result__title {
+  margin-top: 16px;
+  font-weight: 700;
+  color: var(--tag-info-text-color);
+  font-size: var(--font-size-3);
+}
+div .el-result__subtitle {
+  margin-top: 8.28px;
+  font-weight: 400;
+  font-size: var(--font-size-2);
+  line-height: 16px;
+}
+div .el-switch.is-checked .el-switch__core {
+  background-color: var(--color-theme);
+  border-color: var(--color-theme);
+}
+div .el-switch__core {
+  background-color: #87909e;
+  border-color: #87909e;
+}
+div .el-pager li.is-active,
+.el-pager li:hover {
+  color: var(--badge__content--warning);
+}
+
+div .el-tabs__item:hover {
+  color: var(--color-theme);
+}
+div .el-tabs__item.is-active,
+.el-tabs__item:hover {
+  color: var(--color-neutral-1);
+  font-weight: 700;
+  font-size: var(--font-size-5);
+}
+div .el-tabs__item {
+  color: var(--color-neutral-3);
+  font-weight: 700;
+  font-size: var(--font-size-5);
+}
+div .el-tabs__nav-wrap:after {
+  height: 0;
+}
+
+div .el-tabs__active-bar {
+  background-color: var(--color-accent-2);
+}
+
+div .el-radio-button.is-active .el-radio-button__original-radio:not(:disabled)+.el-radio-button__inner {
+  background-color: var(--color-theme);
+  border-color: var(--color-theme);
+  box-shadow:none
+}
+div .el-radio-button__inner:hover {
+  color: var(--color-theme);
+}
+div .el-space {
+  flex-wrap: wrap;
+  margin: 3px 0 0 0;
+}

BIN
src/styles/fonts/Lato-Regular.ttf


BIN
src/styles/fonts/Open-Sans-2.ttf


+ 700 - 0
src/styles/icons/iconfont.css

@@ -0,0 +1,700 @@
+@font-face {
+  font-family: "font_family"; /* Project id 4672385 */
+  src: url('iconfont.woff2?t=1726717215398') format('woff2'),
+       url('iconfont.woff?t=1726717215398') format('woff'),
+       url('iconfont.ttf?t=1726717215398') format('truetype'),
+       url('iconfont.svg?t=1726717215398#font_family') format('svg');
+}
+
+.font_family {
+  font-family: "font_family" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-icon_location_fill_b:before {
+  content: "\e6c0";
+}
+
+.icon-icon_unmark_b:before {
+  content: "\e6c1";
+}
+
+.icon-icon_location_b:before {
+  content: "\e6bf";
+}
+
+.icon-icon_path_b:before {
+  content: "\e6be";
+}
+
+.icon-icon_bold_b:before {
+  content: "\e6bd";
+}
+
+.icon-icon_unlink_b:before {
+  content: "\e6b1";
+}
+
+.icon-icon_revoke__b:before {
+  content: "\e6b2";
+}
+
+.icon-icon_text_links_b:before {
+  content: "\e6b3";
+}
+
+.icon-icon_align__left_b:before {
+  content: "\e6b4";
+}
+
+.icon-icon_redo_b:before {
+  content: "\e6b5";
+}
+
+.icon-icon_underline_b:before {
+  content: "\e6b6";
+}
+
+.icon-icon_quotes_b:before {
+  content: "\e6b7";
+}
+
+.icon-icon_right__align_b:before {
+  content: "\e6b8";
+}
+
+.icon-icon_expression_b:before {
+  content: "\e6b9";
+}
+
+.icon-icon_center__align_b:before {
+  content: "\e6ba";
+}
+
+.icon-icon_italic_b:before {
+  content: "\e6bb";
+}
+
+.icon-icon_cross__out_b:before {
+  content: "\e6bc";
+}
+
+.icon-icon_preview_b:before {
+  content: "\e6a2";
+}
+
+.icon-icon_zoom_in_b:before {
+  content: "\e6a3";
+}
+
+.icon-icon_template_b:before {
+  content: "\e6a4";
+}
+
+.icon-icon_zoom_out_b:before {
+  content: "\e6a5";
+}
+
+.icon-icon_mix_b:before {
+  content: "\e6a6";
+}
+
+.icon-icon_takeoff_b:before {
+  content: "\e6a7";
+}
+
+.icon-icon_sort_b:before {
+  content: "\e6a8";
+}
+
+.icon-icon_landing_b:before {
+  content: "\e6a9";
+}
+
+.icon-icon_fit_to__width_b:before {
+  content: "\e6aa";
+}
+
+.icon-icon_help_b:before {
+  content: "\e6ab";
+}
+
+.icon-icon_crop_b:before {
+  content: "\e6ac";
+}
+
+.icon-icon_filter_b1:before {
+  content: "\e6ad";
+}
+
+.icon-icon_full_screen_b:before {
+  content: "\e6ae";
+}
+
+.icon-icon_download__template_b:before {
+  content: "\e6af";
+}
+
+.icon-icon_airplane_b:before {
+  content: "\e6b0";
+}
+
+.icon-icon_vgm_b:before {
+  content: "\e694";
+}
+
+.icon-icon_ocean_b:before {
+  content: "\e695";
+}
+
+.icon-icon_railway_b:before {
+  content: "\e696";
+}
+
+.icon-icon_truck_b:before {
+  content: "\e697";
+}
+
+.icon-icon_railway3_b:before {
+  content: "\e698";
+}
+
+.icon-icon_communic_ation_b:before {
+  content: "\e699";
+}
+
+.icon-icon_railway2_b:before {
+  content: "\e69a";
+}
+
+.icon-icon_booking_b:before {
+  content: "\e69b";
+}
+
+.icon-icon_booking_order_b:before {
+  content: "\e69c";
+}
+
+.icon-icon_marked_b:before {
+  content: "\e69d";
+}
+
+.icon-icon_bus_b:before {
+  content: "\e69e";
+}
+
+.icon-icon_log_b:before {
+  content: "\e69f";
+}
+
+.icon-icon_focus_b:before {
+  content: "\e6a0";
+}
+
+.icon-icon_ratesheet_b:before {
+  content: "\e6a1";
+}
+
+.icon-icon_report__fill_b:before {
+  content: "\e689";
+}
+
+.icon-icon_quote__fill_b:before {
+  content: "\e68a";
+}
+
+.icon-icon_system__management_fill_b:before {
+  content: "\e68b";
+}
+
+.icon-icon_view__management_b:before {
+  content: "\e68c";
+}
+
+.icon-icon_movetotop_b:before {
+  content: "\e68d";
+}
+
+.icon-icon_tracking__fill_b:before {
+  content: "\e68e";
+}
+
+.icon-icon_booking__fill_b:before {
+  content: "\e68f";
+}
+
+.icon-icon_rate_o:before {
+  content: "\e690";
+}
+
+.icon-icon_all_b:before {
+  content: "\e691";
+}
+
+.icon-icon_movetobottom__b:before {
+  content: "\e692";
+}
+
+.icon-icon_data_fill_b:before {
+  content: "\e693";
+}
+
+.icon-icon_visitor_b:before {
+  content: "\e67e";
+}
+
+.icon-icon_tag_b:before {
+  content: "\e67f";
+}
+
+.icon-icon_reassign__b:before {
+  content: "\e680";
+}
+
+.icon-icon_platenumber_b:before {
+  content: "\e681";
+}
+
+.icon-icon_printing_b:before {
+  content: "\e682";
+}
+
+.icon-icon_time_b:before {
+  content: "\e683";
+}
+
+.icon-icon_email_b:before {
+  content: "\e684";
+}
+
+.icon-icon_picture_b:before {
+  content: "\e685";
+}
+
+.icon-icon_phone_b:before {
+  content: "\e686";
+}
+
+.icon-icon_idcard_b:before {
+  content: "\e687";
+}
+
+.icon-icon_filter_b:before {
+  content: "\e688";
+}
+
+.icon-icon_menu_collapse_b:before {
+  content: "\e675";
+}
+
+.icon-icon_related_b:before {
+  content: "\e676";
+}
+
+.icon-icon_piedata_b:before {
+  content: "\e677";
+}
+
+.icon-icon_jumplink_b:before {
+  content: "\e678";
+}
+
+.icon-icon_cargo_b:before {
+  content: "\e679";
+}
+
+.icon-icon_linedata_b:before {
+  content: "\e67a";
+}
+
+.icon-icon_dimension_b:before {
+  content: "\e67b";
+}
+
+.icon-icon_dragsort__b:before {
+  content: "\e67c";
+}
+
+.icon-icon_group_b:before {
+  content: "\e67d";
+}
+
+.icon-icon_settled_b:before {
+  content: "\e66e";
+}
+
+.icon-icon_adduser_b:before {
+  content: "\e66f";
+}
+
+.icon-icon_module_collapse_b:before {
+  content: "\e670";
+}
+
+.icon-icon_switch_b1:before {
+  content: "\e671";
+}
+
+.icon-icon_serialnumber__b:before {
+  content: "\e672";
+}
+
+.icon-icon_switchupdown__b:before {
+  content: "\e673";
+}
+
+.icon-icon_renew_b:before {
+  content: "\e674";
+}
+
+.icon-icon_application_b:before {
+  content: "\e66d";
+}
+
+.icon-icon_radio_b:before {
+  content: "\e667";
+}
+
+.icon-icon_reduce_b:before {
+  content: "\e668";
+}
+
+.icon-icon_paragraph_b:before {
+  content: "\e669";
+}
+
+.icon-icon_longtext_b:before {
+  content: "\e66a";
+}
+
+.icon-icon_dropdownlist__b:before {
+  content: "\e66b";
+}
+
+.icon-icon_checkbox_b:before {
+  content: "\e66c";
+}
+
+.icon-icon_scan_b:before {
+  content: "\e662";
+}
+
+.icon-icon_wholeprocess__b:before {
+  content: "\e663";
+}
+
+.icon-icon_edoc_b:before {
+  content: "\e664";
+}
+
+.icon-icon_conditional__branch_b:before {
+  content: "\e665";
+}
+
+.icon-icon_review_b:before {
+  content: "\e666";
+}
+
+.icon-icon_slider_b:before {
+  content: "\e655";
+}
+
+.icon-icon_back_b:before {
+  content: "\e656";
+}
+
+.icon-icon_rulesetting__b:before {
+  content: "\e657";
+}
+
+.icon-icon_switch_b:before {
+  content: "\e658";
+}
+
+.icon-icon_table_b:before {
+  content: "\e659";
+}
+
+.icon-icon_matrixlist__b:before {
+  content: "\e65a";
+}
+
+.icon-icon_invisible_b:before {
+  content: "\e65b";
+}
+
+.icon-icon_rate_b:before {
+  content: "\e65c";
+}
+
+.icon-icon_inputnumber_b:before {
+  content: "\e65d";
+}
+
+.icon-icon_disablee__b:before {
+  content: "\e65e";
+}
+
+.icon-icon_inputtree_b:before {
+  content: "\e65f";
+}
+
+.icon-icon_import_b:before {
+  content: "\e660";
+}
+
+.icon-icon_document_b:before {
+  content: "\e661";
+}
+
+.icon-icon_notes_b:before {
+  content: "\e646";
+}
+
+.icon-icon_team_b:before {
+  content: "\e647";
+}
+
+.icon-icon_workflow_b:before {
+  content: "\e648";
+}
+
+.icon-icon_transfer_b:before {
+  content: "\e649";
+}
+
+.icon-icon_workbench_b:before {
+  content: "\e64a";
+}
+
+.icon-icon_request_data_b:before {
+  content: "\e64b";
+}
+
+.icon-icon_remind_b:before {
+  content: "\e64c";
+}
+
+.icon-icon_followup_b:before {
+  content: "\e64d";
+}
+
+.icon-icon_descending_b:before {
+  content: "\e64e";
+}
+
+.icon-icon_department_b:before {
+  content: "\e64f";
+}
+
+.icon-icon_refresh__b:before {
+  content: "\e650";
+}
+
+.icon-icon_business__setting_b:before {
+  content: "\e651";
+}
+
+.icon-icon_admin_b:before {
+  content: "\e652";
+}
+
+.icon-icon_company_b:before {
+  content: "\e653";
+}
+
+.icon-icon_ascending_b:before {
+  content: "\e654";
+}
+
+.icon-icon_view_b:before {
+  content: "\e639";
+}
+
+.icon-icon_createpo_b:before {
+  content: "\e63a";
+}
+
+.icon-icon_submit_b:before {
+  content: "\e63b";
+}
+
+.icon-icon_save_b:before {
+  content: "\e63c";
+}
+
+.icon-icon_upload_b:before {
+  content: "\e63d";
+}
+
+.icon-icon_createinvoice_b:before {
+  content: "\e63e";
+}
+
+.icon-icon_share_b:before {
+  content: "\e63f";
+}
+
+.icon-icon_more_b:before {
+  content: "\e640";
+}
+
+.icon-icon_edit_b:before {
+  content: "\e641";
+}
+
+.icon-icon_draft_b:before {
+  content: "\e642";
+}
+
+.icon-icon_delete_b:before {
+  content: "\e643";
+}
+
+.icon-icon_clone_b:before {
+  content: "\e644";
+}
+
+.icon-icon_closerequest_b:before {
+  content: "\e645";
+}
+
+.icon-icon_top_b:before {
+  content: "\e637";
+}
+
+.icon-icon_exportpo_b:before {
+  content: "\e638";
+}
+
+.icon-icon_info_b:before {
+  content: "\e62e";
+}
+
+.icon-icon_approval__path_b:before {
+  content: "\e62f";
+}
+
+.icon-icon_contract_b:before {
+  content: "\e630";
+}
+
+.icon-icon_download_b:before {
+  content: "\e631";
+}
+
+.icon-icon_document__signing_b:before {
+  content: "\e632";
+}
+
+.icon-icon_commission_b:before {
+  content: "\e633";
+}
+
+.icon-icon_approval_b:before {
+  content: "\e634";
+}
+
+.icon-icon_cancel_b:before {
+  content: "\e635";
+}
+
+.icon-icon_batch__email_b:before {
+  content: "\e636";
+}
+
+.icon-icon_project_b:before {
+  content: "\e627";
+}
+
+.icon-icon_budget_b:before {
+  content: "\e628";
+}
+
+.icon-icon_finance__entity_b:before {
+  content: "\e629";
+}
+
+.icon-icon_return_b:before {
+  content: "\e62a";
+}
+
+.icon-icon_set_b:before {
+  content: "\e62b";
+}
+
+.icon-icon_attendance_b:before {
+  content: "\e62c";
+}
+
+.icon-icon_reset_b:before {
+  content: "\e62d";
+}
+
+.icon-icon_dropdown_b:before {
+  content: "\e61f";
+}
+
+.icon-icon_reject_b:before {
+  content: "\e620";
+}
+
+.icon-icon_dropdown__line_b:before {
+  content: "\e621";
+}
+
+.icon-icon_movedown_b:before {
+  content: "\e622";
+}
+
+.icon-icon_moveup_b:before {
+  content: "\e623";
+}
+
+.icon-icon_date_b:before {
+  content: "\e624";
+}
+
+.icon-icon_column_b:before {
+  content: "\e625";
+}
+
+.icon-icon_add_b:before {
+  content: "\e626";
+}
+
+.icon-icon_password_b:before {
+  content: "\e618";
+}
+
+.icon-icon_notice_b:before {
+  content: "\e619";
+}
+
+.icon-icon_language_b:before {
+  content: "\e61a";
+}
+
+.icon-icon_username_b:before {
+  content: "\e61b";
+}
+
+.icon-icon_tipsfilled_b:before {
+  content: "\e61c";
+}
+
+.icon-icon_search_b:before {
+  content: "\e61d";
+}
+
+.icon-icon_confirm_b:before {
+  content: "\e617";
+}
+
+.icon-icon_export_b:before {
+  content: "\e61e";
+}
+

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
src/styles/icons/iconfont.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 50 - 0
src/styles/icons/iconfont.svg


BIN
src/styles/icons/iconfont.ttf


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä