zs il y a 9 mois
commit
3f7bbe1451

+ 309 - 0
.eslintrc-auto-import.json

@@ -0,0 +1,309 @@
+{
+  "globals": {
+    "Component": true,
+    "ComponentPublicInstance": true,
+    "ComputedRef": true,
+    "EffectScope": true,
+    "ExtractDefaultPropTypes": true,
+    "ExtractPropTypes": true,
+    "ExtractPublicPropTypes": true,
+    "InjectionKey": true,
+    "PropType": true,
+    "Ref": true,
+    "VNode": true,
+    "WritableComputedRef": true,
+    "acceptHMRUpdate": true,
+    "asyncComputed": true,
+    "autoResetRef": true,
+    "computed": true,
+    "computedAsync": true,
+    "computedEager": true,
+    "computedInject": true,
+    "computedWithControl": true,
+    "controlledComputed": true,
+    "controlledRef": true,
+    "createApp": true,
+    "createEventHook": true,
+    "createGlobalState": true,
+    "createInjectionState": true,
+    "createPinia": true,
+    "createReactiveFn": true,
+    "createReusableTemplate": true,
+    "createSharedComposable": true,
+    "createTemplatePromise": true,
+    "createUnrefFn": true,
+    "customRef": true,
+    "debouncedRef": true,
+    "debouncedWatch": true,
+    "defineAsyncComponent": true,
+    "defineComponent": true,
+    "defineStore": true,
+    "eagerComputed": true,
+    "effectScope": true,
+    "extendRef": true,
+    "getActivePinia": true,
+    "getCurrentInstance": true,
+    "getCurrentScope": true,
+    "h": true,
+    "ignorableWatch": true,
+    "inject": true,
+    "injectLocal": true,
+    "isDefined": true,
+    "isProxy": true,
+    "isReactive": true,
+    "isReadonly": true,
+    "isRef": true,
+    "makeDestructurable": true,
+    "mapActions": true,
+    "mapGetters": true,
+    "mapState": true,
+    "mapStores": true,
+    "mapWritableState": true,
+    "markRaw": true,
+    "nextTick": true,
+    "onActivated": true,
+    "onBeforeMount": true,
+    "onBeforeRouteLeave": true,
+    "onBeforeRouteUpdate": true,
+    "onBeforeUnmount": true,
+    "onBeforeUpdate": true,
+    "onClickOutside": true,
+    "onDeactivated": true,
+    "onErrorCaptured": true,
+    "onKeyStroke": true,
+    "onLongPress": true,
+    "onMounted": true,
+    "onRenderTracked": true,
+    "onRenderTriggered": true,
+    "onScopeDispose": true,
+    "onServerPrefetch": true,
+    "onStartTyping": true,
+    "onUnmounted": true,
+    "onUpdated": true,
+    "onWatcherCleanup": true,
+    "pausableWatch": true,
+    "provide": true,
+    "provideLocal": true,
+    "reactify": true,
+    "reactifyObject": true,
+    "reactive": true,
+    "reactiveComputed": true,
+    "reactiveOmit": true,
+    "reactivePick": true,
+    "readonly": true,
+    "ref": true,
+    "refAutoReset": true,
+    "refDebounced": true,
+    "refDefault": true,
+    "refThrottled": true,
+    "refWithControl": true,
+    "resolveComponent": true,
+    "resolveRef": true,
+    "resolveUnref": true,
+    "setActivePinia": true,
+    "setMapStoreSuffix": true,
+    "shallowReactive": true,
+    "shallowReadonly": true,
+    "shallowRef": true,
+    "storeToRefs": true,
+    "syncRef": true,
+    "syncRefs": true,
+    "templateRef": true,
+    "throttledRef": true,
+    "throttledWatch": true,
+    "toRaw": true,
+    "toReactive": true,
+    "toRef": true,
+    "toRefs": true,
+    "toValue": true,
+    "triggerRef": true,
+    "tryOnBeforeMount": true,
+    "tryOnBeforeUnmount": true,
+    "tryOnMounted": true,
+    "tryOnScopeDispose": true,
+    "tryOnUnmounted": true,
+    "unref": true,
+    "unrefElement": true,
+    "until": true,
+    "useActiveElement": true,
+    "useAnimate": true,
+    "useArrayDifference": true,
+    "useArrayEvery": true,
+    "useArrayFilter": true,
+    "useArrayFind": true,
+    "useArrayFindIndex": true,
+    "useArrayFindLast": true,
+    "useArrayIncludes": true,
+    "useArrayJoin": true,
+    "useArrayMap": true,
+    "useArrayReduce": true,
+    "useArraySome": true,
+    "useArrayUnique": true,
+    "useAsyncQueue": true,
+    "useAsyncState": true,
+    "useAttrs": true,
+    "useBase64": true,
+    "useBattery": true,
+    "useBluetooth": true,
+    "useBreakpoints": true,
+    "useBroadcastChannel": true,
+    "useBrowserLocation": true,
+    "useCached": true,
+    "useClipboard": true,
+    "useClipboardItems": true,
+    "useCloned": true,
+    "useColorMode": true,
+    "useConfirmDialog": true,
+    "useCounter": true,
+    "useCssModule": true,
+    "useCssVar": true,
+    "useCssVars": true,
+    "useCurrentElement": true,
+    "useCycleList": true,
+    "useDark": true,
+    "useDateFormat": true,
+    "useDebounce": true,
+    "useDebounceFn": true,
+    "useDebouncedRefHistory": true,
+    "useDeviceMotion": true,
+    "useDeviceOrientation": true,
+    "useDevicePixelRatio": true,
+    "useDevicesList": true,
+    "useDisplayMedia": true,
+    "useDocumentVisibility": true,
+    "useDraggable": true,
+    "useDropZone": true,
+    "useElementBounding": true,
+    "useElementByPoint": true,
+    "useElementHover": true,
+    "useElementSize": true,
+    "useElementVisibility": true,
+    "useEventBus": true,
+    "useEventListener": true,
+    "useEventSource": true,
+    "useEyeDropper": true,
+    "useFavicon": true,
+    "useFetch": true,
+    "useFileDialog": true,
+    "useFileSystemAccess": true,
+    "useFocus": true,
+    "useFocusWithin": true,
+    "useFps": true,
+    "useFullscreen": true,
+    "useGamepad": true,
+    "useGeolocation": true,
+    "useId": true,
+    "useIdle": true,
+    "useImage": true,
+    "useInfiniteScroll": true,
+    "useIntersectionObserver": true,
+    "useInterval": true,
+    "useIntervalFn": true,
+    "useKeyModifier": true,
+    "useLastChanged": true,
+    "useLink": true,
+    "useLocalStorage": true,
+    "useMagicKeys": true,
+    "useManualRefHistory": true,
+    "useMediaControls": true,
+    "useMediaQuery": true,
+    "useMemoize": true,
+    "useMemory": true,
+    "useModel": true,
+    "useMounted": true,
+    "useMouse": true,
+    "useMouseInElement": true,
+    "useMousePressed": true,
+    "useMutationObserver": true,
+    "useNavigatorLanguage": true,
+    "useNetwork": true,
+    "useNow": true,
+    "useObjectUrl": true,
+    "useOffsetPagination": true,
+    "useOnline": true,
+    "usePageLeave": true,
+    "useParallax": true,
+    "useParentElement": true,
+    "usePerformanceObserver": true,
+    "usePermission": true,
+    "usePointer": true,
+    "usePointerLock": true,
+    "usePointerSwipe": true,
+    "usePreferredColorScheme": true,
+    "usePreferredContrast": true,
+    "usePreferredDark": true,
+    "usePreferredLanguages": true,
+    "usePreferredReducedMotion": true,
+    "usePrevious": true,
+    "useRafFn": true,
+    "useRefHistory": true,
+    "useResizeObserver": true,
+    "useRoute": true,
+    "useRouter": true,
+    "useScreenOrientation": true,
+    "useScreenSafeArea": true,
+    "useScriptTag": true,
+    "useScroll": true,
+    "useScrollLock": true,
+    "useSessionStorage": true,
+    "useShare": true,
+    "useSlots": true,
+    "useSorted": true,
+    "useSpeechRecognition": true,
+    "useSpeechSynthesis": true,
+    "useStepper": true,
+    "useStorage": true,
+    "useStorageAsync": true,
+    "useStyleTag": true,
+    "useSupported": true,
+    "useSwipe": true,
+    "useTemplateRef": true,
+    "useTemplateRefsList": true,
+    "useTextDirection": true,
+    "useTextSelection": true,
+    "useTextareaAutosize": true,
+    "useThrottle": true,
+    "useThrottleFn": true,
+    "useThrottledRefHistory": true,
+    "useTimeAgo": true,
+    "useTimeout": true,
+    "useTimeoutFn": true,
+    "useTimeoutPoll": true,
+    "useTimestamp": true,
+    "useTitle": true,
+    "useToNumber": true,
+    "useToString": true,
+    "useToggle": true,
+    "useTransition": true,
+    "useUrlSearchParams": true,
+    "useUserMedia": true,
+    "useVModel": true,
+    "useVModels": true,
+    "useVibrate": true,
+    "useVirtualList": true,
+    "useWakeLock": true,
+    "useWebNotification": true,
+    "useWebSocket": true,
+    "useWebWorker": true,
+    "useWebWorkerFn": true,
+    "useWindowFocus": true,
+    "useWindowScroll": true,
+    "useWindowSize": true,
+    "watch": true,
+    "watchArray": true,
+    "watchAtMost": true,
+    "watchDebounced": true,
+    "watchDeep": true,
+    "watchEffect": true,
+    "watchIgnorable": true,
+    "watchImmediate": true,
+    "watchOnce": true,
+    "watchPausable": true,
+    "watchPostEffect": true,
+    "watchSyncEffect": true,
+    "watchThrottled": true,
+    "watchTriggerable": true,
+    "watchWithFilter": true,
+    "whenever": true
+  }
+}

+ 14 - 0
.eslintrc.cjs

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

+ 30 - 0
.gitignore

@@ -0,0 +1,30 @@
+# 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
+
+/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": 300,
+  "trailingComma": "none"
+}

+ 7 - 0
.vscode/extensions.json

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

+ 35 - 0
README.md

@@ -0,0 +1,35 @@
+# customer
+
+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).
+
+## Customize configuration
+
+See [Vite Configuration Reference](https://vitejs.dev/config/).
+
+## Project Setup
+
+```sh
+npm install
+```
+
+### Compile and Hot-Reload for Development
+
+```sh
+npm run dev
+```
+
+### Compile and Minify for Production
+
+```sh
+npm run build
+```
+
+### Lint with [ESLint](https://eslint.org/)
+
+```sh
+npm run lint
+```

+ 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>智能客服</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.js"></script>
+  </body>
+</html>

+ 10 - 0
jsconfig.json

@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "baseUrl": "./",
+    "paths": {
+      "@/*": ["./src/*"]
+    }
+  },
+  "exclude": ["node_modules", "dist"],
+  "include": ["src/**/*.vue", "**/*.js"]
+}

Fichier diff supprimé car celui-ci est trop grand
+ 3365 - 0
package-lock.json


+ 39 - 0
package.json

@@ -0,0 +1,39 @@
+{
+  "name": "customer",
+  "version": "0.0.0",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "preview": "vite preview",
+    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
+    "format": "prettier --write src/"
+  },
+  "dependencies": {
+    "@ant-design/icons-vue": "^7.0.1",
+    "@vueuse/core": "^11.1.0",
+    "animate.css": "^4.1.1",
+    "ant-design-vue": "^4.2.5",
+    "axios": "^1.7.7",
+    "lodash": "^4.17.21",
+    "moment": "^2.30.1",
+    "naf-core": "^0.1.2",
+    "pinia": "^2.1.7",
+    "vue": "^3.4.29",
+    "vue-router": "^4.3.3",
+    "vuex": "^4.1.0"
+  },
+  "devDependencies": {
+    "@rushstack/eslint-patch": "^1.8.0",
+    "@vitejs/plugin-vue": "^5.0.5",
+    "@vue/eslint-config-prettier": "^9.0.0",
+    "eslint": "^8.57.0",
+    "eslint-plugin-vue": "^9.23.0",
+    "prettier": "^3.2.5",
+    "sass": "^1.79.2",
+    "sass-loader": "^16.0.1",
+    "unplugin-auto-import": "^0.18.3",
+    "vite": "^5.3.1"
+  }
+}

BIN
public/favicon.ico


BIN
public/images/chat-bg.png


BIN
public/images/head-bg.png


BIN
public/images/kf.png


+ 15 - 0
src/App.vue

@@ -0,0 +1,15 @@
+<script setup>
+import { RouterView } from 'vue-router'
+import zhCN from 'ant-design-vue/es/locale/zh_CN'
+import dayjs from 'dayjs'
+import 'dayjs/locale/zh-cn'
+dayjs.locale('zh-cn')
+</script>
+
+<template>
+  <a-config-provider :locale="zhCN">
+    <RouterView />
+  </a-config-provider>
+</template>
+
+<style scoped></style>

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

+ 16 - 0
src/assets/main.css

@@ -0,0 +1,16 @@
+body {
+  margin: 0;
+  color: #303133;
+  font-size: 14px;
+  font-family:
+    Microsoft YaHei,
+    Hiragino Sans GB,
+    Pingfang SC,
+    Arial,
+    Helvetica Neue,
+    Helvetica;
+  font-variant: tabular-nums;
+  line-height: 1.5;
+  -webkit-font-feature-settings: 'tnum';
+  font-feature-settings: 'tnum';
+}

+ 17 - 0
src/main.js

@@ -0,0 +1,17 @@
+import './assets/main.css'
+
+import { createApp } from 'vue'
+import { createPinia } from 'pinia'
+
+import App from './App.vue'
+import router from './router'
+// Antd
+import Antd from 'ant-design-vue'
+import 'ant-design-vue/dist/reset.css'
+
+const app = createApp(App)
+
+app.use(createPinia())
+app.use(router)
+app.use(Antd)
+app.mount('#app')

+ 14 - 0
src/router/index.js

@@ -0,0 +1,14 @@
+import { createRouter, createWebHistory } from 'vue-router'
+
+const router = createRouter({
+  history: createWebHistory(import.meta.env.BASE_URL),
+  routes: [
+    {
+      path: '/',
+      name: 'home',
+      component: () => import('../views/HomePage.vue')
+    }
+  ]
+})
+
+export default router

+ 12 - 0
src/stores/counter.js

@@ -0,0 +1,12 @@
+import { ref, computed } from 'vue'
+import { defineStore } from 'pinia'
+
+export const useCounterStore = defineStore('counter', () => {
+  const count = ref(0)
+  const doubleCount = computed(() => count.value * 2)
+  function increment() {
+    count.value++
+  }
+
+  return { count, doubleCount, increment }
+})

+ 349 - 0
src/views/HomePage.vue

@@ -0,0 +1,349 @@
+<template>
+  <div id="index">
+    <div class="one">
+      <a-image :src="head" width="100%" :preview="false" />
+    </div>
+    <div class="two">
+      <div class="left">
+        <div class="left_1" ref="scrollRef">
+          <a-spin size="large" :spinning="spinning">
+            <div class="chat" v-for="(item, index) in list" :key="index" :class="[item.user ? 'message_right' : 'message_left']">
+              <div class="chat_right" v-if="item.user">
+                <span>{{ item.content || '暂无内容' }}</span>
+              </div>
+              <div class="chat_left" v-else>
+                <span>{{ item.content || '暂无内容' }}</span>
+              </div>
+            </div>
+            <div class="time">
+              <p>{{ time }}</p>
+            </div>
+            <div class="kf">
+              <div class="kf_1">
+                <a-avatar :src="kf" />
+              </div>
+              <div class="kf_2">您好,小智正在为您服务</div>
+            </div>
+            <div class="chat" v-for="(item, index) in messageList" :key="index" :class="[item.user ? 'message_right' : 'message_left']">
+              <div class="chat_right" v-if="item.user">
+                <span>{{ item.content || '暂无内容' }}</span>
+              </div>
+              <div class="chat_left" v-else>
+                <span>{{ item.content || '暂无内容' }}</span>
+              </div>
+            </div>
+          </a-spin>
+        </div>
+        <div class="left_2">
+          <div class="search"></div>
+          <div class="text">
+            <a-textarea :bordered="false" v-model:value="text" placeholder="请输入您的问题" allow-clear :auto-size="{ minRows: 4, maxRows: 5 }" />
+          </div>
+          <div class="send">
+            <span>shift+enter换行,enter发送</span>
+            <a-button type="primary" @click="onSend">发送</a-button>
+          </div>
+        </div>
+      </div>
+      <div class="right">
+        <div class="right_1">
+          <div class="title">
+            <div class="title_1">常见问题</div>
+            <div class="title_2" @click="toChange"><SyncOutlined /> <span>换一批</span></div>
+          </div>
+          <div class="list">
+            <div class="list_1" v-for="(item, index) in problemList" :key="index" @click="toSend(item)">
+              <div class="index">{{ index + 1 }}</div>
+              <div class="content">{{ item.content || '暂无内容' }}</div>
+            </div>
+          </div>
+        </div>
+        <div class="right_1">
+          <div class="title">
+            <div class="title_1">历史记录</div>
+            <div class="title_2" @click="toDel"><DeleteOutlined /> <span>清空</span></div>
+          </div>
+          <div class="list">
+            <div class="list_2" v-for="(item, index) in historyList" :key="index" @click="toSend(item)">
+              <div class="content">{{ item.content || '暂无内容' }}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import moment from 'moment'
+// 图片引入
+import head from '/images/head-bg.png'
+import kf from '/images/kf.png'
+import { DeleteOutlined, SyncOutlined } from '@ant-design/icons-vue'
+const user = ref({ id: '1' })
+const time = computed(() => moment().format('YYYY-MM-DD HH:mm:ss'))
+const text = ref('')
+// 最底部
+const scrollRef = ref(null)
+// 加载中
+const spinning = ref(false)
+// 聊天记录
+const list = ref([
+  { id: '1', content: '任务书提交不成功,显示暂未开启', time: '2024-09-20 11:13', user: user.value.id },
+  { id: '2', content: '提供账号(身份证号码+密码)登录,确认项目名称以及是否填写完毕,提交。是二级代理商缓存的问题,最好使用360安全浏览器(极速模式),清理缓存,或使用笔记本电脑连接手机热点,然后等待30分钟左右再操作即可。', time: '2024-09-20 11:13' },
+  { id: '3', content: '变更单位名称', time: '2024-09-20 11:13', user: user.value.id },
+  { id: '4', content: '如果没有在研项目或有在研项目已结项,提供工商局变更手续扫描件发送至邮箱 3165837280@qq.com,并将最新营业执照上传至单位账号-信息维护中,可变更。如果有在研项目未结项,请联系咨询相关处室。', time: '2024-09-20 11:13' },
+  { id: '5', content: '任务书提交后是否能修改?', time: '2024-09-20 11:13', user: user.value.id },
+  { id: '6', content: '不能修改,只有审核不通过被退回时能修改。只要上方没有【保存】键都不能修改。', time: '2024-09-20 11:13' },
+  { id: '7', content: '中省直单位的所属科技管理部门是否能选科技厅?', time: '2024-09-20 11:13', user: user.value.id },
+  { id: '8', content: '如单位账号-单位性质处已显示中直或者省直,可直接选择科技厅(系统默认选择科技厅),中省直单位如单位性质处未选择中直或者省直,需联系系统后台,提供中省直财政预算代码,待确认无误后,可更改单位性质,可选科技厅。', time: '2024-09-20 11:13' }
+])
+// 常见问题
+const problemList = ref([
+  { id: '1', content: '任务书提交不成功,显示暂未开启' },
+  { id: '2', content: '变更单位名称' },
+  { id: '3', content: '任务书提交后是否能修改?' },
+  { id: '4', content: '中省直单位的所属科技管理部门是否能选科技厅?' },
+  { id: '5', content: '项目负责人注册时未找到本单位' },
+  { id: '6', content: '任务书提交不成功,显示暂未开启' }
+])
+// 历史记录
+const historyList = ref([
+  { id: '1', content: '单位注册时名称写错,能修改吗?' },
+  { id: '2', content: '用户名及密码找回' }
+])
+// 实时记录
+const messageList = ref([])
+// 请求
+onMounted(async () => {
+  spinning.value = true
+  await search()
+  spinning.value = false
+})
+const search = async () => {
+  let res
+  messageList.value.push({ content: 'Hi,很高兴为您服务,请问有什么需要帮助?', time: moment().format('YYYY-MM-DD HH:mm:ss') })
+  await scrollToBottom()
+}
+// 发送问题
+const toSend = async (item) => {
+  spinning.value = true
+  const info = { content: item.content, time: moment().format('YYYY-MM-DD HH:mm:ss'), user: user.value.id }
+  messageList.value.push(info)
+  await scrollToBottom()
+  spinning.value = false
+}
+// 换一批
+const toChange = () => {
+  console.log('换一批')
+}
+// 清空
+const toDel = () => {
+  console.log('清空')
+}
+// 发送
+const onSend = async () => {
+  spinning.value = true
+  const info = { content: text.value, time: moment().format('YYYY-MM-DD HH:mm:ss'), user: user.value.id }
+  messageList.value.push(info)
+  await scrollToBottom()
+  spinning.value = false
+}
+// 滚动到最底部
+const scrollToBottom = () => {
+  if (scrollRef.value) {
+    scrollRef.value.scrollTo({ top: scrollRef.value.scrollHeight, behavior: 'smooth' })
+  }
+}
+</script>
+<style scoped lang="scss">
+.one {
+  width: 100%;
+}
+.two {
+  display: flex;
+  height: 91vh;
+  width: 100%;
+  .left {
+    width: 80%;
+    height: 100%;
+    .left_1 {
+      padding: 16px;
+      height: 690px;
+      -webkit-box-sizing: border-box;
+      box-sizing: border-box;
+      overflow: auto;
+      background: url(/images/chat-bg.png) no-repeat bottom right #f6f9fb;
+      .chat {
+        .chat_left {
+          background-color: #fff;
+          border-radius: 0 15px 15px 15px;
+          padding: 10px 20px;
+          font-size: 16px;
+          max-width: 560px;
+        }
+        .chat_right {
+          max-width: 560px;
+          background: rgba(0, 119, 255, 0.644);
+          padding: 10px 20px;
+          font-size: 16px;
+          border-radius: 15px 0 15px 15px;
+          color: #fff;
+        }
+      }
+      .message_left {
+        display: flex;
+        justify-content: flex-start;
+        margin: 10px 0;
+      }
+      .message_right {
+        display: flex;
+        justify-content: flex-end;
+        margin: 10px 0;
+      }
+      .time {
+        text-align: center;
+        padding: 10px;
+        p {
+          display: inline-block;
+          height: 26px;
+          line-height: 26px;
+          text-align: center;
+          background-color: #d9e1e6;
+          border-radius: 4px;
+          font-size: 12px;
+          color: #fff;
+          padding: 0 12px;
+        }
+      }
+      .kf {
+        position: relative;
+        text-align: center;
+        .kf_1 {
+          position: absolute;
+          top: -20%;
+          left: 49%;
+        }
+        .kf_2 {
+          background: #fff;
+          border-radius: 10px;
+          display: inline-block;
+          padding: 30px 10px 10px;
+          line-height: 1;
+          min-width: 200px;
+        }
+      }
+    }
+    .left_2 {
+      height: 150px;
+      background: #fff;
+      border-top: 1px solid #f6f6f6;
+      -webkit-box-sizing: border-box;
+      box-sizing: border-box;
+      .send {
+        padding: 10px;
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        span {
+          color: #ccc;
+          margin: 0 10px 0 0;
+        }
+      }
+    }
+  }
+  .right {
+    background-color: #fff;
+    width: 20%;
+    height: 100%;
+    .right_1 {
+      border-bottom: 1px solid #ddd;
+      padding: 10px 18px;
+      .title {
+        display: flex;
+        justify-content: space-between;
+        margin-bottom: 10px;
+        .title_1 {
+          font-size: 20px;
+          color: #333;
+        }
+        .title_2 {
+          cursor: pointer;
+          font-size: 14px;
+          color: #999;
+        }
+      }
+      .list {
+        max-height: 530px;
+        overflow: auto;
+        .list_1 {
+          display: flex;
+          align-items: center;
+          cursor: pointer;
+          margin-bottom: 10px;
+          .index {
+            width: 20px;
+            height: 20px;
+            line-height: 20px;
+            background-color: #bad7fc;
+            text-align: center;
+            color: #fff;
+          }
+          .content {
+            font-size: 14px;
+            color: #666;
+            margin-left: 12px;
+            width: 100%;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+          }
+        }
+        .list_2 {
+          display: flex;
+          flex-flow: wrap;
+          .content {
+            padding: 6px 10px;
+            background-color: #f5f7fa;
+            text-align: center;
+            border-radius: 18px;
+            font-size: 14px;
+            color: #676767;
+            margin-right: 6px;
+            margin-bottom: 6px;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+    .right_1:last-child {
+      border-bottom: none;
+    }
+  }
+}
+@media screen and (max-width: 1280px) {
+  #index {
+    min-width: 1920px;
+    margin: 0 auto;
+  }
+}
+@media screen and (min-width: 1921px) {
+  #index {
+    max-width: 1920px;
+    margin: 0 auto;
+  }
+}
+/* 自定义整个滚动条 */
+::-webkit-scrollbar {
+  width: 5px; /* 滚动条宽度 */
+}
+
+/* 自定义滚动条的滑块(thumb) */
+::-webkit-scrollbar-thumb {
+  background: #cfd6dd; /* 滑块颜色 */
+}
+/* 当hover或active状态时,自定义滑块的颜色 */
+::-webkit-scrollbar-thumb:hover {
+  background: #cfd6dd;
+}
+</style>

+ 30 - 0
vite.config.js

@@ -0,0 +1,30 @@
+import AutoImport from 'unplugin-auto-import/vite'
+import { fileURLToPath, URL } from 'node:url'
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+export default defineConfig({
+  plugins: [
+    vue(),
+    AutoImport({
+      // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
+      imports: ['vue', '@vueuse/core', 'pinia', 'vue-router'],
+      resolvers: [],
+      eslintrc: {
+        enabled: false,
+        filepath: './.eslintrc-auto-import.json',
+        globalsPropValue: true
+      },
+      vueTemplate: true
+    })
+  ],
+  resolve: {
+    alias: {
+      '@': fileURLToPath(new URL('./src', import.meta.url))
+    }
+  },
+  // 预加载项目必需的组件
+  optimizeDeps: {
+    include: ['vue', 'vue-router', 'pinia', 'axios', '@vueuse/core']
+  }
+})