提交 4e581bb4 作者: Hao

拉取最新代码

父级 3cd0f8bb
NODE_ENV=development
VITE_USER_APP_API_URL=192.168.31.135
\ No newline at end of file
NODE_ENV=production
VITE_USER_APP_API_URL=192.168.31.101
\ No newline at end of file
......@@ -15,9 +15,7 @@ module.exports = defineConfig({
}),
],
},
// chainWebpack: config => {
// config.plugin('html').use(HtmlWebpackPlugin, [{
// title:'客服端',
// }])
// }
chainWebpack: config => {
console.log(config,'config')
}
})
\ No newline at end of file
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
......
......@@ -11,6 +11,7 @@ declare module 'vue' {
ElAside: typeof import('element-plus/es')['ElAside']
ElButton: typeof import('element-plus/es')['ElButton']
ElContainer: typeof import('element-plus/es')['ElContainer']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElFooter: typeof import('element-plus/es')['ElFooter']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
......@@ -19,12 +20,16 @@ declare module 'vue' {
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElMain: typeof import('element-plus/es')['ElMain']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
EmotionComponent: typeof import('./src/components/EmotionComponent.vue')['default']
IndexComponent: typeof import('./src/components/IndexComponent.vue')['default']
LogingComponent: typeof import('./src/components/loging/logingComponent.vue')['default']
MenuComponent: typeof import('./src/components/Menu/MenuComponent.vue')['default']
RightClickMenu: typeof import('./src/components/RightClickMenu.vue')['default']
RightClickMenu: typeof import('./src/components/Menu/RightClickMenu.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
ShopList: typeof import('./src/components/ShopList.vue')['default']
}
}
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>客服端</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>客服端</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "tokcos-socket-web-ts",
"version": "0.1.0",
"private": true,
"name": "min-demo",
"version": "0.0.1",
"type": "module",
"license": "MIT",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
"build": "vue-tsc --noEmit && vite build --mode production",
"serve": "vite --mode development",
"preview": "vite preview"
},
"dependencies": {
"@babel/core": "^7.24.3",
"@babel/types": "^7.24.0",
"@element-plus/icons-vue": "^2.3.1",
"@luohc92/vue3-image-viewer": "^1.0.0",
"axios": "^1.6.7",
"core-js": "^3.8.3",
"@tinymce/tinymce-vue": "^4.0.7",
"@vitalets/google-translate-api": "^9.2.0",
"amfe-flexible": "^2.2.1",
"axios": "^0.27.2",
"clipboard": "^2.0.11",
"copy-webpack-plugin": "^11.0.0",
"cos-js-sdk-v5": "^1.7.0",
"cos-wx-sdk-v5": "^1.6.0",
"element-plus": "^2.6.1",
"echarts": "^5.3.3",
"element-plus": "^2.2.14",
"emoji.json": "^15.1.0",
"html-webpack-plugin": "^5.6.0",
"i18n-jsautotranslate": "^2.6.0",
"json-format": "^1.0.1",
"min-comp": "^0.0.4",
"mockjs": "^1.1.0",
"moment": "^2.30.1",
"pinia": "^2.1.7",
"particles.vue3": "^2.2.3",
"pinia": "^2.0.20",
"pinia-plugin-persistedstate": "^3.2.1",
"socket.io-client": "^4.7.4",
"unplugin-auto-import": "0.16.1",
"unplugin-vue-components": "^0.25.2",
"vue": "^3.2.13",
"vue-native-websocket": "^2.0.15",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
"prismjs": "^1.28.0",
"sass": "^1.54.5",
"sass-loader": "^13.0.2",
"three": "^0.143.0",
"tsparticles": "^2.2.3",
"tunnel": "^0.0.6",
"v-clipboard": "^3.0.0-next.1",
"vant": "^3.6.0",
"vite-plugin-dts": "^1.4.1",
"vite-plugin-md": "^0.20.2",
"vue": "^3.2.37",
"vue-router": "^4.1.3",
"vue3-uuid": "^1.0.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-typescript": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"@vue/eslint-config-typescript": "^9.1.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"typescript": "~4.5.5"
"@types/node": "^12.20.24",
"@vitejs/plugin-vue": "^3.0.3",
"rollup-plugin-copy": "^3.4.0",
"typescript": "^4.6.4",
"unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0",
"vite": "^3.0.7",
"vite-plugin-auto-i18n": "^0.0.9",
"vue-tsc": "^0.39.5"
}
}
No preview for this file type
src/assets/login.jpg

311.8 KB | W: | H:

src/assets/login.jpg

2.3 MB | W: | H:

src/assets/login.jpg
src/assets/login.jpg
src/assets/login.jpg
src/assets/login.jpg
  • 2-up
  • Swipe
  • Onion skin
<?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="1713946537964" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="49096" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M896 346.8c-0.1 0 0 0 0 0 0-0.9-0.1-1.7-0.2-2.5 0-0.1 0-0.3-0.1-0.4-0.2-1.7-0.5-3.3-1-4.9-0.5-1.7-1-3.3-1.7-4.9v-0.1c-0.3-0.8-0.7-1.5-1.1-2.3v-0.1c-0.4-0.7-0.8-1.5-1.2-2.2-0.1-0.1-0.1-0.2-0.2-0.3-0.4-0.6-0.8-1.2-1.3-1.9-0.1-0.1-0.1-0.2-0.2-0.2-0.5-0.6-1-1.3-1.5-1.9-0.1-0.1-0.2-0.3-0.4-0.4-0.5-0.6-1-1.2-1.6-1.7l-0.1-0.1L637.3 74.5c-0.6-0.6-1.2-1.1-1.8-1.6-0.1-0.1-0.3-0.2-0.4-0.4-0.6-0.5-1.2-1-1.9-1.5-0.1 0-0.1-0.1-0.2-0.1-0.6-0.5-1.3-0.9-1.9-1.3-0.1-0.1-0.2-0.1-0.3-0.2-0.7-0.4-1.4-0.9-2.2-1.3-0.8-0.4-1.5-0.8-2.3-1.1h-0.1c-1.6-0.7-3.2-1.3-4.9-1.7-1.6-0.4-3.2-0.8-4.9-1-0.1 0-0.3 0-0.4-0.1-1.4-0.2-2.8-0.3-4.3-0.3H164c-19.9 0-36 16.1-36 36v823.3c0 19.9 16.1 36 36 36h696c19.9 0 36-16.1 36-36V346.8zM647.8 186.9l125.4 125.6H647.8V186.9zM200 887.2V135.9h375.8v212.7c0 19.9 16.1 36 36 36H824v502.7H200z" fill="#2c2c2c" p-id="49097"></path><path d="M363.5 661.5c-7.2 6.3-15.8 9.5-25.8 9.5-13.5 0-24.5-5-33-15S292 629.3 292 605.7c0-22.2 4.3-38.2 12.9-48.1 8.6-9.9 19.8-14.9 33.6-14.9 10 0 18.5 2.8 25.5 8.4s11.6 13.2 13.8 22.9l37.2-8.9c-4.2-14.9-10.6-26.3-19-34.3-14.2-13.5-32.7-20.2-55.5-20.2-26.1 0-47.1 8.6-63.1 25.7s-24 41.2-24 72.2c0 29.3 8 52.4 23.9 69.3 15.9 16.9 36.2 25.3 60.9 25.3 20 0 36.5-4.9 49.4-14.8 13-9.9 22.3-24.9 27.9-45.3L379 631.6c-3.1 13.6-8.3 23.6-15.5 29.9z m198-64.3c-8.8-4.6-22.3-9.1-40.6-13.4s-29.8-8.5-34.5-12.4c-3.7-3.1-5.6-6.9-5.6-11.3 0-4.8 2-8.7 6-11.6 6.2-4.5 14.7-6.7 25.6-6.7 10.6 0 18.5 2.1 23.8 6.3 5.3 4.2 8.7 11.1 10.3 20.6l37.6-1.7c-0.6-17.1-6.8-30.8-18.6-41s-29.4-15.4-52.7-15.4c-14.3 0-26.5 2.2-36.6 6.5-10.1 4.3-17.9 10.6-23.2 18.9-5.4 8.3-8.1 17.1-8.1 26.6 0 14.7 5.7 27.2 17.1 37.5 8.1 7.3 22.3 13.4 42.4 18.4 15.7 3.9 25.7 6.6 30.1 8.1 6.4 2.3 10.9 5 13.5 8.1 2.6 3.1 3.9 6.8 3.9 11.2 0 6.9-3.1 12.8-9.2 18-6.1 5.1-15.3 7.7-27.4 7.7-11.4 0-20.5-2.9-27.2-8.6-6.7-5.8-11.2-14.8-13.4-27l-36.6 3.6c2.5 20.8 10 36.7 22.6 47.5 12.6 10.9 30.7 16.3 54.2 16.3 16.2 0 29.7-2.3 40.5-6.8s19.2-11.4 25.1-20.8c5.9-9.3 8.9-19.3 8.9-30 0-11.8-2.5-21.6-7.4-29.6s-11.7-14.3-20.5-19z m128.4 54.4l-47.1-137.7h-40.7L668.6 700h40.1l66.7-186.1h-39.9z" fill="#2c2c2c" p-id="49098"></path></svg>
\ No newline at end of file
......@@ -2,8 +2,7 @@
import { useUserStore } from '../store/modules/user'
import axios from "axios";
const instance = axios.create({
baseURL: "http://192.168.31.123:8080", // 设置基础 URL
// baseURL:'',
baseURL: `http://${import.meta.env.VITE_USER_APP_API_URL}:8080`, // 设置基础 URL
timeout: 1000, // 设置请求超时时间
});
instance.interceptors.request.use(
......
......@@ -43,7 +43,7 @@ const checkMesssages = (query: any) => {
const getUploadConfigInfo = (query: any) => {
return http({
url: "/getUploadConfigInfo",
url: "/upload/getUploadConfigInfo",
method: "get",
data: query,
});
......@@ -52,7 +52,7 @@ const getUploadConfigInfo = (query: any) => {
const upload = (query: any) => {
return http({
url: "/sys/common/upload",
method: "get",
method: "post",
data: query,
});
};
......
......@@ -37,14 +37,13 @@
ref="elAutocomplete"
placeholder="输入信息"
contenteditable="true"
style="outline: none; height: 150px;"
style="outline: none; "
@paste.prevent="handlePaste"
@focus="removeDefaultContent"
@input="handleSelect"
@blur="addDefaultContent"
></div>
</div>
<emotion
v-if="showEmotion"
style="position: absolute; top: calc(100% - 465px); background: #fff;"
......@@ -62,7 +61,7 @@
</template>
<script lang="ts" setup>
import Emotion from './IndexComponent.vue'
import emotion from './IndexComponent.vue'
import { ElLoading } from 'element-plus'
import { ref, watch, defineEmits, defineExpose } from 'vue'
import { upLoadFilesHander } from '../minxins/UploadMixin'
......@@ -247,8 +246,8 @@ defineExpose({
}
.el-autocomplete {
width: 100%;
height: calc(100vh - 732px);
max-width: 100%;
max-height: 150px;
overflow: auto;
}
.el-autocomplete img {
......
......@@ -16,13 +16,14 @@
import { ref, watch, defineEmits, defineExpose, defineProps } from 'vue'
const list = ref([])
import * as emoji from 'emoji.json'
console.log(emoji,'打印emoji')
console.log(emoji,'emoji')
const getList = () => {
list.value = emoji.slice(0, 50)
list.value.push(emoji[55])
list.value.push(emoji[56])
list.value.push(emoji[57])
list.value.push(emoji[60])
let info = emoji.default
list.value = info.slice(0, 50)
list.value.push(info[55])
list.value.push(info[56])
list.value.push(info[57])
list.value.push(info[60])
}
const emits = defineEmits(['emotion'])
const clickHandler = (i: number | string) => {
......
<template>
<div class="select-box">
<div class="active">复制</div>
<div>翻译</div>
<div>设为客户名称</div>
<div>设置国家/地区</div>
<div>设为Email</div>
<div>设为watchApp</div>
</div>
</template>
<script></script>
<style scoped lang="scss">
.select-box {
display: flex;
width: 136px;
padding: var(--Spacing-md, 8px);
flex-direction: column;
align-items: flex-start;
gap: var(--Spacing-xs, 4px);
border-radius: var(--Radius-md, 8px);
background: var(--color-bg-Program-White, #fff);
box-shadow: 0 2px 12px 0 #08112914;
div {
padding: 6px 8px;
height: 32px;
line-height: 32px;
}
.active {
display: flex;
padding: var(--Spacing-sm, 6px) var(--Spacing-md, 8px);
align-items: center;
gap: var(--Spacing-none, 0);
align-self: stretch;
color: #fff;
border-radius: 4px;
background: #010914;
font-size: 14px;
}
}
</style>
import { Callback } from "./../../../node_modules/escalade/sync/index.d";
import { h, render, reactive, ref, defineEmits } from "vue";
import RightClickMenu from "./RightClickMenu.vue";
import { copyText } from "@/utils/index";
export default function useMenu(e: MouseEvent) {
const contextMenuVisible = ref(true);
const contextMenuTop = ref(0);
......@@ -9,6 +11,9 @@ export default function useMenu(e: MouseEvent) {
let containerEl = reactive<HTMLElement | any>(null);
let vnode = reactive<any>(null);
let props = reactive<any>({});
let itemInfo = reactive<any>({});
let callbackFn = reactive<any>(function () {});
let emit = defineEmits(["RightClickItemEmits"]);
const setComponent = () => {
props = {
visible: contextMenuVisible.value,
......@@ -22,7 +27,12 @@ export default function useMenu(e: MouseEvent) {
],
active: contextMenuIndex.value,
"onUpdate:info": (info: any) => {
contextMenuIndex.value = info.index;
let { index } = info;
contextMenuIndex.value = index;
callbackFn({
...info,
itemInfo: itemInfo.value,
});
setComponent();
},
};
......@@ -36,7 +46,10 @@ export default function useMenu(e: MouseEvent) {
if (containerEl) containerEl.style.position = "fixed";
if (containerEl) containerEl.style["z-index"] = "1000";
};
const showContextMenu = (event: any, item: any) => {
const showContextMenu = (event: any, item: any, callback: Function) => {
itemInfo.value = item;
callbackFn = callback;
//阻止默认右键事件
event.preventDefault();
//菜单可见
......@@ -48,7 +61,6 @@ export default function useMenu(e: MouseEvent) {
// 检测是否超出浏览器视口区域 一个菜单40px*6个
const menuHeight = 300; // 右键菜单的高度
const windowHeight = window.innerHeight;
if (event.clientY + menuHeight > windowHeight) {
// 如果右键菜单超出视口底部,调整位置为向上弹出
contextMenuTop.value -= menuHeight;
......
......@@ -17,7 +17,7 @@
</teleport>
</template>
<script setup lang="ts">
import { defineProps, onMounted, defineEmits } from 'vue'
import { defineProps, defineEmits } from 'vue'
defineProps(['top', 'left', 'visible', 'menuList', 'active'])
const emit = defineEmits(['update:info'])
const handleItemClick = (item: any, index: any) => {
......
<template>
<teleport to="body">
<div
id="select-box"
v-if="visible"
:style="{ top: `${top}px`, left: `${left}px` }"
>
<ul
v-for="(item, index) in menuList"
:class="{ active: active == index }"
:key="index"
@click.stop="handleItemClick(item,index)"
>
<li >{{ item }}</li>
</ul>
<!-- <div>翻译</div>
<div>设为客户名称</div>
<div>设置国家/地区</div>
<div>设为Email</div>
<div>设为watchApp</div> -->
</div>
</teleport>
</template>
<script setup lang="ts">
import { defineProps } from 'vue'
defineProps(['top', 'left', 'handleItemClick', 'visible', 'menuList', 'active'])
</script>
<style scoped lang="scss">
#select-box {
position: fixed;
z-index: 1000;
display: flex;
width: 136px;
padding: var(--Spacing-md, 8px);
flex-direction: column;
align-items: flex-start;
gap: var(--Spacing-xs, 4px);
border-radius: var(--Radius-md, 8px);
background: var(--color-bg-Program-White, #fff);
box-shadow: 0 2px 12px 0 #08112914;
ul {
padding: 6px 8px;
height: 32px;
line-height: 32px;
}
.active {
display: flex;
padding: var(--Spacing-sm, 6px) var(--Spacing-md, 8px);
align-items: center;
gap: var(--Spacing-none, 0);
align-self: stretch;
color: #fff;
border-radius: 4px;
background: #010914;
font-size: 14px;
}
}
</style>
<template>
<el-dialog
v-model="dialogVisible"
title="添加商品"
:before-close="handleClose"
>
<el-table
:data="tableData"
ref="multipleTableRef"
border
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="name" label="商品名称" width="300" />
<el-table-column
prop="productImg"
label="商品图片"
width="100"
align="center"
>
<template #default="scope">
<el-image
style="width: 40px; height: 40px;"
:src="scope.row.productImg"
/>
</template>
</el-table-column>
<el-table-column prop="productPrice" label="商品价格" width="300">
<template #default="scope">${{ scope.row.productPrice }}</template>
</el-table-column>
<el-table-column prop="productPrice" label="商品库存" width="300">
<template #default="scope">{{ scope.row.stock }}</template>
</el-table-column>
</el-table>
<el-pagination
background
layout="prev, pager, next"
:total="tableData.length"
/>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleOk">
确认
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { require } from '@/utils/index'
import { ref, defineExpose } from 'vue'
const tableData = [
{
name: '商品商品商品商品商品商品商品商品商品商品商品商品1',
productImg: require('../assets/login.jpg'),
productPrice: '10',
stock: 10,
unit:'USD'
},
{
name: '商品商品商品商品商品商品商品商品商品商品商品2',
productImg: require('../assets/login.jpg'),
productPrice: '10',
stock: 10,
unit:'USD'
},
{
name: '商品商品商品商品商品商品商品商品商品商品商品3',
productImg: require('../assets/login.jpg'),
productPrice: '10',
stock: 10,
unit:'USD'
},
{
name: '商品商品商品商品商品商品商品商品商品商品商品4',
productImg: require('../assets/login.jpg'),
productPrice: '10',
stock: 10,
unit:'USD'
},
]
const selectionValues = ref([])
const multipleTableRef = ref(null)
//勾选
const emits = defineEmits(['selectionChange'])
const handleSelectionChange = (e) => {
selectionValues.value = e;
}
let dialogVisible = ref(false)
const handleClose = () => {
dialogVisible.value = false
}
const handleOk = ()=>{
emits('selectionChange',selectionValues.value)
toggleSelection()
dialogVisible.value = false
}
const toggleSelection = (rows?:User[])=>{
if (rows) {
rows.forEach((row) => {
multipleTableRef.value!.toggleRowSelection(row, undefined)
})
} else {
multipleTableRef.value!.clearSelection()
}
}
defineExpose({
dialogShow(res: any) {
dialogVisible.value = true
},
})
</script>
<style>
.el-pagination {
display: flex;
margin-top: 10px;
justify-content: end;
}
</style>
import '../../lang/index'
import langJSON from '../../lang/index.json'
const langMap = {
zhcn: window?.lang?.zhcn || _getJSONKey('zh-cn', langJSON),
en: window?.lang?.en || _getJSONKey('en', langJSON),
ko: window?.lang?.ko || _getJSONKey('ko', langJSON),
ja: window?.lang?.ja || _getJSONKey('ja', langJSON),
}
const lang = window.localStorage.getItem('lang') || 'zhcn'
console.log(langMap[lang])
window.$t.locale(langMap[lang], 'lang')
......@@ -4,12 +4,12 @@ import router from "./router";
import store from "./store/index";
import "./assets/css/reset.css";
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
import { useUserStore } from "./store/modules/user";
import "@/permission"; // permission control
import "element-plus/dist/index.css";
import "../src/mocks/mock";
const app = createApp(App);
app.use(store).use(router).mount("#app");
import Clipboard from 'v-clipboard'
app.use(Clipboard).use(store).use(router).mount("#app");
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
......
// const COS = require("cos-wx-sdk-v5");
// import { ElMessage } from "element-plus";
// import { upload, getUploadConfigInfo } from "../axios/model/user";
// export default function () {
// interface UploadMixin {
// uploadMixinPath: string;
// uploadMixinType: string;
// uploadMixinCredentials: any;
// uploadMixinTimeStamp: number;
// }
// const uploadMixin: UploadMixin = {
// uploadMixinPath: "",
// uploadMixinType: "",
// uploadMixinCredentials: {},
// uploadMixinTimeStamp: 0,
// };
// const upLoadFilesHander = (tempFilePaths:any, tempFiles:any, zip:any) => {
// return new Promise((resolve) => {
// if (tempFiles.length != 0) {
// if (typeof upLoadHander !== "function") return;
// let uploadObj = {};
// let uploadNum = tempFiles.length;
// uploadObj.length = tempFiles.length;
// //处理上传结果函数
// function loadHandler({ success, message }:any, i) {
// uploadNum = uploadNum - 1;
// uploadObj[i] = message;
// if (!success) {
// uploadObj[i] = "";
// ElMessage({
// message: `[${i + 1}]上传失败,请重新上传!`,
// type: "none",
// });
// }
// if (uploadNum == 0) {
// const arr = Array.from(uploadObj);
// // ;
// resolve({ success: true, result: arr });
// }
// }
// //进行上传
// tempFiles.forEach((file:any, i:any) => {
// upLoadHander({
// path: tempFilePaths[i],
// file: file.path,
// zip: zip || "",
// onSuccess: ({ success, message }:any) => {
// loadHandler({ success, message }, i);
// },
// onError: (res:any) => {
// loadHandler({ success: false, message: "" }, i);
// },
// });
// });
// } else {
// resolve({ success: true, result: [] });
// }
// });
// };
// const upLoadHander = (obj:any) => {
// const { path, file, biz } = obj;
// const pathArr = (path || "").split("/");
// const pathStr = pathArr[pathArr.length - 1];
// const fileName = (pathStr || "").split(".");
// let fileInfo = {
// fileTyle: fileName.length > 1 ? fileName[fileName.length - 1] : "",
// fileName: fileName[0],
// biz: biz || "temp",
// file: file,
// };
// const none = (async function hander(noCredentials) {
// let res = {
// result:{}
// },
// staticDomain = "",
// resResult = true;
// //noCredentials变量控制是否走对象存储
// if (noCredentials) {
// let query = {}
// res = await getUploadConfigInfo(query);
// console.log(res)
// if (res.code === 200 && res.result) {
// let result = res.result
// uploadMixin.uploadMixinPath = result.upLoadPath;
// uploadMixin.uploadMixinType = result.uploadType;
// staticDomain = result.staticDomain || "https://cdn.tikcos.cn";
// if (uploadMixin.uploadMixinType === "txcos") {
// const credentials = result.credentials;
// uploadMixin.uploadMixinCredentials = {
// TmpSecretId: credentials.tmpSecretId,
// TmpSecretKey: credentials.tmpSecretKey,
// SecurityToken: credentials.sessionToken,
// StartTime: result.startTime,
// ExpiredTime: result.expiredTime,
// };
// }
// } else {
// resResult = false;
// }
// }
// //resResult判断接口是否正常
// if (resResult) {
// if (uploadMixin.uploadMixinType == "txcos") {
// //走对象存储
// const cos = new COS({
// getAuthorization: (options:any, callback:any) => {
// callback(uploadMixin.uploadMixinCredentials);
// },
// });
// const tempFolder = fileInfo.biz === "temp" ? "" : `${fileInfo.biz}/`;
// const folder = `${fileInfo.fileName}_${new Date().getTime()}.${
// fileInfo.fileTyle
// }`;
// let result = res.result || {}
// cos.postObject(
// {
// FilePath: fileInfo.file,
// Bucket: result.bucketName || "tikcos-1257774783",
// Region: result.regionid || "ap-guangzhou",
// Key: uploadMixin.uploadMixinPath + tempFolder + folder,
// Body: fileInfo.file,
// onProgress: function (progressData:any) {
// obj.onProgress && obj.onProgress(progressData);
// },
// },
// (err:any, data:any) => {
// if (!err && data.statusCode === 200) {
// const imgurl = `${staticDomain}/${uploadMixin.uploadMixinPath}${tempFolder}${folder}`;
// obj.onSuccess({
// success: true,
// message: imgurl,
// });
// } else {
// obj.onError({
// success: false,
// message: err || "图片上传失败",
// });
// }
// }
// );
// } else {
// //走系统上传
// upload({
// biz: fileInfo.biz,
// file: fileInfo.file,
// }).then((uploadRes:any) => {
// if (uploadRes.success && uploadRes.message) {
// //保存绝对路径,不然小程序会有问题
// let url = uploadRes.message;
// obj.onSuccess({ success: true, message: url });
// } else {
// obj.onError({
// success: false,
// message: uploadRes.message || "图片上传失败",
// });
// }
// })
// } else {
// obj.onError({
// success: false,
// message: "服务接口报错",
// });
// }}
// })(true);
// };
// }
import { reactive, watch, ref, defineEmits, defineExpose } from "vue";
import { ElMessage } from "element-plus";
import { upload, getUploadConfigInfo } from "../axios/model/user";
// const COS = require("cos-wx-sdk-v5");
import axios from "axios";
import COS from "cos-js-sdk-v5";
interface UploadMixin {
uploadMixinPath: string;
uploadMixinType: string;
uploadMixinCredentials: any;
uploadMixinTimeStamp: number;
upLoadMixinResult: object;
}
const uploadMixin: UploadMixin = {
uploadMixinPath: "",
uploadMixinType: "",
uploadMixinCredentials: {},
uploadMixinTimeStamp: 0,
upLoadMixinResult: {},
};
interface CustomAxiosResponse {
code: number;
......@@ -259,23 +92,28 @@ export const upLoadHander = async (obj: any) => {
//noCredentials变量控制是否走对象存储
if (noCredentials) {
const query = {};
const res:any = await getUploadConfigInfo(query);
// console.log(res1,'res')
// console.log(res);
const res: any = await getUploadConfigInfo(query);
if (res.code === 200 && res.result) {
const result = res.result;
uploadMixin.uploadMixinPath = result.upLoadPath;
uploadMixin.uploadMixinType = result.uploadType;
staticDomain = result.staticDomain || "https://cdn.tikcos.cn";
if (uploadMixin.uploadMixinType === "txcos") {
const credentials = result.credentials;
console.log(result.response, " result.response");
const ress = res.result.response;
const credentials = ress.credentials;
uploadMixin.uploadMixinCredentials = {
TmpSecretId: credentials?.tmpSecretId,
TmpSecretKey: credentials?.tmpSecretKey,
SecurityToken: credentials?.sessionToken,
StartTime: result.startTime,
ExpiredTime: result.expiredTime,
StartTime: ress?.startTime,
ExpiredTime: ress?.expiredTime,
};
console.log(result, "result");
console.log(
uploadMixin.uploadMixinCredentials,
" uploadMixin.uploadMixinCredentials"
);
}
} else {
resResult = false;
......@@ -284,51 +122,84 @@ export const upLoadHander = async (obj: any) => {
//resResult判断接口是否正常
if (resResult) {
const query = {};
const res:any = await getUploadConfigInfo(query);
if (uploadMixin.uploadMixinType == "txcos") {
// const res: any = await getUploadConfigInfo(query);
console.log(
uploadMixin.uploadMixinCredentials,
" console.log(uploadMixin.uploadMixinCredentials)"
);
const result: any = uploadMixin.upLoadMixinResult;
if (uploadMixin.uploadMixinType === "txcos") {
//走对象存储
const cos = new COS({
getAuthorization: (options: any, callback: any) => {
getAuthorization: (options, callback) => {
callback(uploadMixin.uploadMixinCredentials);
},
});
const tempFolder = fileInfo.biz === "temp" ? "" : `${fileInfo.biz}/`;
const folder = `${fileInfo.fileName}_${new Date().getTime()}.${
fileInfo.fileTyle
}`;
const result = res.result || {};
cos.putObject(
{
// FilePath: fileInfo.file,
Bucket: result.bucketName || "tikcos-1257774783",
Region: result.regionid || "ap-guangzhou",
Key: uploadMixin.uploadMixinPath + tempFolder + folder,
Body: fileInfo.file,
onProgress: function (progressData: any) {
obj.onProgress && obj.onProgress(progressData);
onProgress: function (progressData) {
console.log(progressData, "ada");
obj.onProgress(progressData);
},
},
async (err: any, data: any) => {
(err, data) => {
console.log(err, data, "打印一下");
console.log({ success: true });
console.log(
`${staticDomain}/${uploadMixin.uploadMixinPath}${tempFolder}${folder}`,
"打印一下,数据"
);
if (!err && data.statusCode === 200) {
const imgurl = `${staticDomain}/${uploadMixin.uploadMixinPath}${tempFolder}${folder}`;
obj.onSuccess({
success: true,
message: imgurl,
});
obj.onSuccess({ success: true, message: imgurl });
} else {
obj.onError({
success: false,
message: data.message || "图片上传失败",
});
obj.onError({ success: false, message: err || "图片上传失败" });
}
}
);
} else {
// 其他存储类型暂不支持
obj.onError({
success: false,
message: "服务接口报错",
});
//走系统上传
let VUE_APP_API_URL = import.meta.env.VITE_USER_APP_API_URL;
let newFile = fileInfo.file;
if (/[\u4e00-\u9fa5]/.test(newFile.name)) {
const folder = newFile.name.replace(/[\u4e00-\u9fa5]{1,}/g, "_");
newFile = new File([newFile], folder, { type: newFile.type });
}
let formData = new FormData();
formData.append("biz", fileInfo.biz);
formData.append("file", newFile);
const uploadRes = await axios.post(`http://${VUE_APP_API_URL}:8080/sys/common/upload`,
formData,
{
headers: { ...obj.headers },
processData: false,
contentType: false,
async: false,
}
);
if (uploadRes.success && uploadRes.message) {
//保存绝对路径,不然小程序会有问题
let url = uploadRes.message;
url = uploadRes.message.replaceAll("//", "/");
const pre = url.startsWith("/") ? "" : "/";
url = `http://${VUE_APP_API_URL}/sys/common/static` + pre + url;
obj.onSuccess({ success: true, message: url });
} else {
obj.onError({
success: false,
message: uploadRes.message || "图片上传失败",
});
}
}
} else {
obj.onError({
......
const Mock = require('mockjs')
import Mock from 'mockjs'
Mock.mock("/kf/auth/login", "post", () => {
return {
code: "200",
......
......@@ -21,7 +21,7 @@ const routes: Array<RouteRecordRaw> = [
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
history: createWebHistory(),
routes,
});
......
......@@ -4,4 +4,5 @@ declare module '*.vue' {
const component: DefineComponent<{}, {}, any>
export default component
}
declare module 'cos-wx-sdk-v5';
\ No newline at end of file
declare module 'cos-wx-sdk-v5';
declare module 'i18n-jsautotranslate'
\ No newline at end of file
......@@ -6,7 +6,9 @@ export const useUserStore = defineStore("user", {
return {
isConnected: false, //连接状态
messages: [],
customerInfo: {},
customerInfo: {
sessionId: "",
},
count: 0,
userInfo: {
username: "admin",
......@@ -37,11 +39,10 @@ export const useUserStore = defineStore("user", {
return {
...item,
username: item.id,
userImg:"https://cdn.lirimall.com//lirigo/filetempImage/新鲜水果_1661668973048.png",
userImg: "https://img2.baidu.com/it/u=3369130612,2858330241&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1713891600&t=a5f6e80de48d2a4a5158a68aeafa0ecf",
messages: [],
};
});
console.log(this.userList);
resolve(result);
}
});
......
import ClipboardJS from "clipboard";
import { ElMessage } from "element-plus";
export function getShortDate(): string {
const now = new Date();
let month: string = (now.getMonth() + 1).toString();
......@@ -19,3 +21,30 @@ export function getShortDate(): string {
return month + "-" + day + " " + hour + ":" + minutes;
}
export const require = (imgPath: any) => {
try {
const handlePath = imgPath.replace("@", "..");
return new URL(handlePath, import.meta.url).href;
} catch (error) {
console.warn(error);
}
};
export const copyText = (text) => {
const textarea = document.createElement("textarea");
textarea.value = text;
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
ElMessage("复制成功!");
return new Promise((resolve, reject) => {
document.execCommand("copy") ? resolve() : reject();
textarea.remove();
});
};
export const regexText = (html) => {
var result = html.replace(/<[^<>]+>/g, "");
console.log(result,'result')
return result;
};
......@@ -14,7 +14,6 @@ function creatWebSocket(wsUrl: string) {
} else {
console.log("当前浏览器不支持 WebSocket");
}
try {
initWebSocket(wsUrl); // 初始化websocket连接
} catch (e) {
......@@ -65,13 +64,13 @@ function websocketOpen() {
// 数据接收
function websocketonmessage(e: MessageEvent<any>) {
const res = JSON.parse(e.data); // 解析JSON格式的数据
console.log(res,'res')
console.log(res, "res");
if (res.command == 11) {
//将数据放在store中
// 下面的判断则是后台返回的接收到的数据 如何处理自己决定
useUserStore()
.setUserListMessages(res.data)
.then();
setTimeout(() => {
useUserStore().setUserListMessages(res.data).then();
}, 10);
}
}
......
<template>
<div class="common-layout">
<el-container>
<el-aside width="280px">
<el-aside width="280px" class="el-aside-left">
<el-header class="el-header-left">
<el-input placeholder="搜索" />
</el-header>
<div active-text-color="#000" background-color="#fff">
<div
active-text-color="#000"
background-co
lor="#fff"
class="el-menu-item-box"
>
<div
class="el-menu-item"
:class="getMenuItem(item)"
......@@ -27,10 +32,18 @@
</div>
</div>
<div class="user-reply-box">
<span class="user-reply">
{{ item.content }}
<span class="user-reply" v-if="item.content.includes('{')">
[询价单]
</span>
<span class="user-reply" v-else-if="item.msgType == 1">
[图文]
</span>
<div class="count">1</div>
<span
class="user-reply"
v-else
v-html="item.content"
></span>
<!-- <div class="count">1</div> -->
</div>
</div>
</div>
......@@ -49,59 +62,120 @@
id="srollId"
ref="srollId"
:style="{
height: '600px',
height: '60vh',
width: '100%',
border: '1px solid #ccc',
}"
>
<div
class="message-container"
v-for="(message, index) in messages"
:key="index"
:class="getMessageClass(message)"
>
<div class="time">{{ message.time }}</div>
<div v-if="isSelf(message)" class="message-container">
<div class="bubble" @contextmenu="showContextMenu($event, item)">
<div v-if="message?.msgType == 0" class="message">
<div class="content" v-html="message?.content"></div>
<div class="contentFy" v-html="message?.contentFy"></div>
</div>
<div v-else class="img-wraper">
<el-image
:src="message?.content"
:preview-src-list="[message?.content]"
/>
<div v-for="(message, index) in messages" :key="message.id">
<div
class="message-container"
v-if="message.msgType == 3"
:class="getMessageClass(message)"
@click.prevent="handleMessageClick($event)"
>
<div class="classSendLink">
<div class="classSendDiv">
<div class="classSend-img">
<img :src="message.content.productImg" />
</div>
<div class="classSend-price">
<div class="class-send-title">
{{ message.content.productName }}
</div>
<div class="class-send-box">
<div class="class-send-price">
{{ message.content.price }}
</div>
<!-- <div class="send">{{ message.content.link }}</div> -->
</div>
</div>
</div>
</div>
<div class="avatar">
<img
src="../assets/logo.png"
alt="Avatar"
class="avatar-image"
/>
</div>
</div>
<div v-if="!isSelf(message)" class="message-container">
<div class="avatar">
<img :src="message?.userImg" class="avatar-image" />
<!-- 询价单 -->
<div
class="message-container message-container-left"
v-else-if="message.msgType == 4"
>
<div class="inquiry-list">
<div class="inquiry-top">
<div class="product-left">
<div class="product-category">
{{ message.content.purchaseQuantity }}
</div>
<div class="product-name">
{{ message.content.ProductName }}
</div>
</div>
<div>
<div class="product-count">
{{ message.content.price }}
</div>
<div class="from-china">
{{ message.content.EmailAddress }}
</div>
</div>
</div>
<div class="product-info">
{{ message.content.otherRequirements }}
</div>
<div class="design-requirements">
<div>{{ message.content.flieName }}</div>
<div class="img">
<img :src="require('../assets/icon_download.png')" />
</div>
</div>
</div>
<div class="bubble" @contextmenu="showContextMenu($event, item)">
<div v-if="message?.msgType == 0" class="message">
<div class="content" v-html="message?.content"></div>
<div class="contentFy" v-html="message?.contentFy"></div>
</div>
<div
v-else
class="message-container"
:key="index"
:class="getMessageClass(message)"
@click.prevent="handleMessageClick($event)"
>
<div class="time">{{ message.time }}</div>
<div v-if="isSelf(message)" class="message-container">
<div
class="bubble"
@contextmenu="showContextMenu($event, message, callbackFn)"
>
<div v-if="message?.msgType == 0" class="message">
<div class="content" v-html="message?.content"></div>
<div class="contentFy" v-html="message?.contentFy"></div>
</div>
<div v-else class="img-wraper">
<el-image
:src="message?.content"
:preview-src-list="[message?.content]"
/>
</div>
</div>
<div v-else class="img-wraper">
<el-image
:src="message?.content"
:preview-src-list="[message?.content]"
/>
</div>
<div v-if="!isSelf(message)" class="message-container">
<div
class="bubble"
@contextmenu="showContextMenu($event, message, callbackFn)"
>
<div v-if="message?.msgType == 0" class="message">
<div class="content" v-html="message?.content"></div>
<div class="contentFy" v-html="message?.contentFy"></div>
</div>
<div v-else class="img-wraper">
<el-image
:src="message?.content"
:preview-src-list="[message?.content]"
/>
</div>
</div>
</div>
</div>
</div>
</el-main>
<el-footer class="el-footer">
<el-footer
class="el-footer-view"
:style="{ border: '1px solid #E9ECF1' }"
>
<AutomaticPrompt
@keydown.enter="handleButtonClick"
@updateState="getState"
......@@ -122,43 +196,52 @@
<el-aside width="400px">
<div>
<el-header class="el-header-right">
<img src="../assets/logo.png" alt="Avatar" />
<img src="../assets/xunjia.svg" alt="Avatar" />
<div class="name">询价单</div>
</el-header>
<div class="customer-info user-wrapper">
<div class="customer-info-right">
<div class="customer-info-box">
<div
class="customer-info-box"
v-for="(item, index) in inquiryInfo"
:key="index"
>
<div class="avatar-box">
<img src="../assets/shop.jpg" alt="Avatar" />
<img :src="item.productImg" alt="Avatar" />
</div>
<div class="avatar-right">
<div class="avatar-right-name">
{{ inquiryInfo.name }}
</div>
<div class="avatar-right-price">
<div>{{ inquiryInfo.price }}</div>
<div>{{ inquiryInfo.unit }}</div>
<div>
<div class="avatar-right-name">
{{ item.name }}
</div>
<div class="avatar-right-price">
<div>{{ item.productPrice }}</div>
<div>{{ item.unit }}</div>
</div>
</div>
<div class="avatar-input-box">
<div>
<el-input-number
class="avatar-number-input"
:min="1"
@change="handleChange"
v-model="ruleForm.count"
v-model="item.count"
:max="10"
/>
</div>
<div class="avatar-input-right">
<div class="change">更换</div>
<div class="delete">删除</div>
<div class="change" @click="handleChange(item, index)">
更换
</div>
<div class="delete" @click="handleDelete(item, index)">
删除
</div>
</div>
</div>
</div>
</div>
<div class="add">
<img src="../assets/add-line.png" />
<div>添加</div>
<div @click="handlerAdd(shopListRef)">添加</div>
</div>
</div>
<div class="form">
......@@ -173,17 +256,13 @@
<el-form-item label="客户名称" prop="customerName">
<el-input
v-model="ruleForm.customerName"
type="password"
placeholder="默认展示"
autocomplete="off"
/>
</el-form-item>
<el-form-item label="国家/地区" prop="countriesRegions">
<el-input
v-model="ruleForm.countriesRegions"
type="password"
placeholder="默认展示"
autocomplete="off"
/>
</el-form-item>
<el-form-item label="Email" prop="Email">
......@@ -216,27 +295,31 @@
:rows="8"
/>
</el-form-item>
<el-button
type="primary"
plain
style="width: 50px;"
@click.stop="sumbitFuleForm(ruleFormRef)"
>
发送
</el-button>
</el-form>
</div>
</div>
<el-footer class="footer-view">
<el-button
type="primary"
plain
style="width: 50px;"
@click.stop="sumbitFuleForm(ruleFormRef)"
>
发送
</el-button>
</el-footer>
</div>
</el-aside>
</el-container>
<ShopList ref="shopListRef" @selectionChange="selectionChange"></ShopList>
</div>
</template>
<script lang="ts" setup>
import '../assets/font/iconfont.css'
import { ElMessage } from 'element-plus'
import { require, copyText } from '@/utils/index'
import { ref, onMounted, watch, nextTick, reactive, computed } from 'vue'
import { getShortDate } from '../utils/index'
import { getShortDate, regexText } from '../utils/index'
import { useUserStore } from '../store/modules/user'
import AutomaticPrompt from '@/components/AutomaticPrompt.vue'
import ImageViewer from '@luohc92/vue3-image-viewer'
......@@ -246,20 +329,18 @@ import { initWebSocket } from '../utils/websocket'
import '@luohc92/vue3-image-viewer/dist/style.css'
import { InquiryAdd, checkMesssages } from '../axios/model/user'
import useMenu from '@/components/Menu/RightClickMenu'
let { showContextMenu, hideContextMenu } = useMenu()
const ruleForm = ref({
count: 1,
})
import ShopList from '@/components/ShopList.vue'
let { showContextMenu } = useMenu()
console.log(useMenu(), 'useMenu')
const ruleForm = ref({})
const ruleFormRef = ref<FormInstance>()
const shopListRef = ref(null)
const messages = ref([])
const getUseUserStore = useUserStore()
const list = ref([])
const automaticPromptRef = ref('')
const inquiryInfo = ref({
price: '20.00',
unit: 'USD',
name: 'Industrial 5V 12V RS232 RS-232 Parallel PCI PC',
})
const inquiryInfo = ref([])
console.log(shopListRef)
const rules = reactive({
customerName: [
{
......@@ -312,7 +393,9 @@ let currentInfo = ref({
})
const connectMsg = () => {
const useUser = useUserStore()
const toIp = `ws://192.168.31.123:8081?type=kf&code=${getUseUserStore.userInfo?.username}`
const toIp = `ws://${
import.meta.env.VITE_USER_APP_API_URL
}:8081?type=kf&code=${getUseUserStore.userInfo?.username}`
useUser.connect()
initWebSocket(toIp)
useUser.setUserListMessages({}).then((res: any) => {
......@@ -341,14 +424,10 @@ const getCheckMesssages = async (res: any) => {
if (success) {
currentInfo.value = JSON.parse(JSON.stringify(res))
result.forEach((item: any) => {
item.userImg =
'https://cdn.lirimall.com//lirigo/filetempImage/新鲜水果_1661668973048.png'
})
currentInfo.value.messages = result.map((item: any) => {
return {
...item,
}
if ([3, 4].includes(item.msgType))
item.content = JSON.parse(item.content)
})
currentInfo.value.messages = result
messages.value = result
}
getUseUserStore.setCustomerInfo(currentInfo.value)
......@@ -389,6 +468,32 @@ const setSrollHeight = () => {
if (div) div.scrollTop = div?.scrollHeight
})
}
//获取右键弹窗每一项触发的事件
const callbackFn = (obj: object) => {
let { index, itemInfo } = obj
let content = regexText(itemInfo.content)
let ruleFormInfo = ruleForm.value
if (index == 0) {
//复制
copyText(content)
} else if (index == 1) {
//翻译
} else if (index == 2) {
//设为客户名称
ruleFormInfo.customerName = content
} else if (index == 3) {
//设置国家/地区
ruleFormInfo.countriesRegions = content
} else if (index == 4) {
//设为Email
ruleFormInfo.Email = content
} else if (index == 5) {
//设为watchApp
ruleFormInfo.WatchApp = content
}
}
//切换聊天人
const handleMenuClick = (item: object) => {
getCheckMesssages(item)
......@@ -422,6 +527,14 @@ const handleButtonClick = () => {
automaticPromptRef.value.setState('')
}
//商品询价单更换和删除
const handleChange = (item, index) => {
shopListRef.value.dialogShow(item, index)
}
const handleDelete = (item, index) => {
inquiryInfo.value.splice(index, 1)
}
//提交询价单
const sumbitFuleForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
......@@ -443,6 +556,10 @@ const sumbitFuleForm = (formEl: FormInstance | undefined) => {
}
})
}
//添加商品
const handlerAdd = (e) => {
shopListRef.value.dialogShow()
}
//消息框样式动态选择
const getMessageClass = (message: any) => {
return isSelf.value(message)
......@@ -453,8 +570,113 @@ const getMessageClass = (message: any) => {
const getMenuItem = (item: any) => {
return item.username == currentInfo.value?.username ? 'is-active' : ''
}
const handleMessageClick = (event: any) => {
const target = event.target
if (target.tagName === 'A') {
if (target.innerHTML === '解决') {
alert('感谢您的使用')
} else if (target.innerHTML === '未解决') {
alert('很抱歉未能解决你的问题')
} else {
handleLinkClick(target.innerHTML)
}
} else if (target.tagName === 'IMG') {
// 点击的图片进行放大操作
ImageViewer({
//切记额images这个参数是数组,我的target.valueof().src值是一个http的图片地址
images: [target.valueOf().src],
curIndex: 0,
zIndex: 2000,
showDownload: true,
showThumbnail: true,
handlePosition: 'bottom',
maskBgColor: 'rgba(0,0,0,0.7)',
})
}
}
const handleLinkClick = (msg: string) => {
messages.value.push({ content: msg, isSent: true })
}
const selectionChange = (arr: any) => {
inquiryInfo.value = arr.map((item) => {
item.count = 1
return item
})
console.log(inquiryInfo.value)
}
</script>
<style lang="scss" scoped>
.inquiry-list {
background: #fff;
display: flex;
width: 360px;
padding: 12px 12px 8px 12px;
flex-direction: column;
justify-content: center;
align-items: flex-start;
border-radius: 8px 0 8px 8px;
border: 1px solid #e9ecf1;
.inquiry-top {
margin-bottom: 8px;
width: 100%;
display: flex;
justify-content: space-between;
.product-left {
display: flex;
flex-direction: column;
justify-content: space-between;
.product-category {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
color: #0c203d;
text-overflow: ellipsis;
font-family: 'Inter';
font-size: 14px;
font-style: normal;
font-weight: 500;
margin-bottom: 6px;
}
.product-name {
font-family: 'Inter';
font-size: 14px;
font-style: normal;
font-weight: 500;
}
}
}
.design-requirements {
width: 336px;
height: 36px;
justify-content: space-between;
line-height: 36px;
margin-top: 8px;
padding: 0px 8px;
display: flex;
align-items: center;
background: #f6f9fc;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
align-self: stretch;
overflow: hidden;
border-radius: 4px;
color: #475263;
text-overflow: ellipsis;
font-family: 'Inter';
font-size: 12px;
font-style: normal;
font-weight: 400;
.img {
width: 20px;
height: 20px;
img {
width: 100%;
height: 100%;
}
}
}
}
.el-header-left {
height: 76px;
width: 100%;
......@@ -481,7 +703,9 @@ const getMenuItem = (item: any) => {
.el-header-center {
height: 76px;
width: 100%;
border: 1px solid #e6e8ed;
border-top: 1px solid #e6e8ed;
border-bottom: 1px solid #e6e8ed;
border-right: 1px solid #e6e8ed;
padding: 16px 24px;
display: flex;
justify-content: space-between;
......@@ -501,6 +725,7 @@ const getMenuItem = (item: any) => {
height: 76px;
width: 100%;
border: 1px solid #e6e8ed;
border-left: 0px;
display: flex;
align-items: center;
img {
......@@ -517,12 +742,12 @@ const getMenuItem = (item: any) => {
line-height: 20px;
}
}
.el-footer {
.el-footer-view {
width: 100%;
border: 1px solid #ccc;
border-top: 0px;
border-left: 0px;
border-bottom: 0px;
padding: 10px;
height: calc(100vh - 600px - 76px);
height: calc(100vh - 76px - 60vh);
position: relative;
.btn-send {
position: absolute;
......@@ -552,6 +777,7 @@ const getMenuItem = (item: any) => {
display: flex;
align-items: center;
img {
border-radius: 4px;
width: 40px;
height: 40px;
}
......@@ -606,7 +832,7 @@ const getMenuItem = (item: any) => {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
max-width: 80px;
max-width: 170px;
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
margin-right: 10px;
......@@ -639,10 +865,14 @@ const getMenuItem = (item: any) => {
font-weight: 400;
}
}
.customer-info {
overflow: scroll;
height: calc(100vh - 154px);
}
.customer-info-right {
.customer-info-box {
display: flex;
margin-bottom: 10px;
.avatar-box {
width: 88px;
height: 88px;
......@@ -660,6 +890,9 @@ const getMenuItem = (item: any) => {
align-items: center;
margin-top: 8px;
justify-content: space-between;
&:nth-child(1) {
margin-top: 0px;
}
.change {
margin-right: 27px;
color: #010914;
......@@ -683,6 +916,9 @@ const getMenuItem = (item: any) => {
}
.avatar-right {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.avatar-right-name {
display: -webkit-box;
-webkit-box-orient: vertical;
......@@ -722,6 +958,33 @@ const getMenuItem = (item: any) => {
.el-input__wrapper {
width: 48px;
}
.avatar-input-box {
:deep(.el-input-number__increase),
:deep(.el-input-number__decrease) {
width: 32px;
height: 32px;
border-radius: 0px;
border: 1px solid #dedfe0;
top: 0px;
}
:deep(.el-input__wrapper) {
width: 32px;
height: 32px;
.el-input__inner {
outline: none !important;
}
.is_focus {
box-shadow: 0 important;
}
}
}
:deep(.el-input-number__decrease) {
left: 0px;
}
:deep(.el-input-number__increase) {
right: 0px;
}
.user-wrapper {
padding: 16px;
}
......@@ -828,7 +1091,73 @@ const getMenuItem = (item: any) => {
border-radius: 8px 0 8px 8px;
}
}
.class-send-box {
display: flex;
justify-content: space-between;
.send {
justify-content: center;
align-items: center;
border-radius: 4px;
border: 1px solid #c7cdd4;
color: #031327;
font-family: 'PingFang SC';
font-size: 12px;
width: 56px;
font-weight: 400;
line-height: 20px;
text-align: center;
}
}
.class-send-title {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
align-self: stretch;
overflow: hidden;
color: #0c203d;
text-overflow: ellipsis;
font-family: 'Helvetica Neue';
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px;
}
.classSend-price {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.class-send-price {
color: #0c203d;
font-feature-settings: 'clig' off, 'liga' off;
font-family: 'Helvetica Neue';
font-size: 18px;
font-style: normal;
font-weight: 700;
line-height: 24px;
letter-spacing: 0.72px;
}
.classSendLink {
background: #fff;
.classSend-img {
width: 72px;
height: 72px;
margin-right: 12px;
img {
width: 100%;
height: 100%;
}
}
.classSendDiv {
display: flex;
padding-bottom: 8px;
}
width: 360px;
padding: 12px 12px 0px 12px;
border-radius: 8px 0 8px 8px;
border: 1px solid #e9ecf1;
}
.message-container-left {
justify-content: flex-start;
.bubble {
......@@ -842,6 +1171,8 @@ const getMenuItem = (item: any) => {
}
.avatar-number-input {
width: 102px !important;
height: 32px !important;
border-radius: 0px !important;
}
.add {
display: flex;
......@@ -850,7 +1181,7 @@ const getMenuItem = (item: any) => {
justify-content: center;
align-items: center;
gap: 4px;
border-radius: var(--Radius-xs, 4px);
border-radius: 4px;
border: var(--Edges-zero, 1px) solid var(--color-Stroke-Weak, #e6e8ed);
background: var(--color-bg-Program-White, #fff);
width: 72px;
......@@ -895,4 +1226,32 @@ const getMenuItem = (item: any) => {
background: #f2f3f5;
}
}
.el-menu-item-box {
height: calc(100vh - 76px);
overflow: auto;
}
.delete,
.change {
cursor: pointer;
}
#srollId {
border-right: 1px solid #e6e8ed;
}
.el-aside-left {
border-right: 1px solid #e6e8ed;
}
.footer-view {
height: max-content;
}
.product-info {
align-self: stretch;
color: #475263;
font-family: 'Inter';
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px;
padding-bottom: 8px;
border-bottom: 1px solid #e6e8ed;
}
</style>
declare module "*.vue" {
import type { DefineComponent } from "vue";
const component: DefineComponent<{}, {}, any>;
export default component;
}
import { defineConfig } from "vite";
import Components from "unplugin-vue-components/vite";
import vuePluginsAutoI18n from "vite-plugin-auto-i18n";
import createVuePlugin from '@vitejs/plugin-vue';
import AutoImport from "unplugin-auto-import/vite";
import { VantResolver } from "unplugin-vue-components/resolvers";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import path from "path";
export default defineConfig({
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
plugins: [
createVuePlugin(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [VantResolver(), ElementPlusResolver()],
}),
],
server: {
host: "0.0.0.0",
port: 8082,
open: false,
},
});
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论