提交 9829b6de 作者: Hao

添加拼团抢购

父级 f2f9a1e6
......@@ -4,5 +4,5 @@
// Generated by unplugin-auto-import
export {}
declare global {
const ElMessage: typeof import('element-plus/es')['ElMessage']
}
......@@ -16,6 +16,7 @@
"cos-wx-sdk-v5": "^1.6.0",
"element-plus": "^2.6.1",
"emoji.json": "^15.1.0",
"html-webpack-plugin": "^5.6.0",
"mockjs": "^1.1.0",
"moment": "^2.30.1",
"pinia": "^2.1.7",
......
......@@ -5,7 +5,7 @@
<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><%= htmlWebpackPlugin.options.title %></title>
<title>客服端</title>
</head>
<body>
<noscript>
......
// axios.js
import axios from "axios";
const instance = axios.create({
baseURL: "/api", // 设置基础 URL
// baseURL: "http://192.168.31.228:8080", // 设置基础 URL
baseURL:'',
timeout: 1000, // 设置请求超时时间
});
......@@ -10,7 +11,7 @@ instance.interceptors.request.use(
// 在发送请求之前做些什么,例如添加 token
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
config.headers['X-Access-Token'] = `Bearer ${token}`;
}
return config;
},
......@@ -29,5 +30,4 @@ instance.interceptors.response.use(
return Promise.reject(error);
}
);
export default instance;
......@@ -2,10 +2,11 @@ import http from "../index";
//登录
const Login = (query: any) => {
return http({
url: `/login`,
method: "get",
url: `/kf/auth/login`,
method: "post",
data: query,
});
};
//新增询价单
const InquiryAdd = (query: any) => {
......@@ -56,6 +57,14 @@ const upload = (query: any) => {
data: query,
});
};
//删除
const deleteUserList = (query: any) => {
return http({
url: `/deleteUserList`,
method: "delete",
params:query
});
};
export {
Login,
InquiryAdd,
......@@ -64,4 +73,5 @@ export {
checkMesssages,
upload,
getUploadConfigInfo,
deleteUserList
};
......@@ -31,24 +31,18 @@
快捷回复
</div>
</div>
<!-- <el-autocomplete
class="autocomplete"
v-model="state"
:fetch-suggestions="querySearchAsync"
placeholder="请输入问题"
type="textarg"
@select="handleSelect"
ref="automaticPromptRef"
/> -->
<el-input
v-model="state"
ref="automaticPromptRef"
class="el-autocomplete"
<div
class="el-autocomplete textarea"
id="el-autocomplete"
ref="elAutocomplete"
placeholder="输入信息"
type="textarea"
resize="none"
@change="handleSelect"
/>
contenteditable="true"
style="outline: none; height: 150px;"
@paste.prevent="handlePaste"
@focus="removeDefaultContent"
@input="handleSelect"
@blur="addDefaultContent"
></div>
</div>
<emotion
......@@ -73,30 +67,27 @@ import { ElLoading } from 'element-plus'
import { ref, watch, defineEmits, defineExpose } from 'vue'
import { upLoadFilesHander } from '../minxins/UploadMixin'
import axios from 'axios'
const state = ref('')
const inputVal = ref('')
const elAutocomplete = ref(null)
const file = ref(null)
interface LinkItem {
value: string
link: string
}
// uploadMixin()
const imgShowWidth = ref<number>(50)
const imgShowHeight = ref<number>(50)
const showEmotion = ref<boolean>(false)
const automaticPromptRef = ref(null)
const links = ref<LinkItem[]>([])
const handleEmotion = (i) => {
state.value += i
elAutocomplete.value.innerHTML += i
inputVal.value = elAutocomplete.value.innerHTML
showEmotion.value = false
automaticPromptRef.value.focus()
elAutocomplete.value.focus()
}
const upfile = () => {
file.value.click()
}
//上传的数据
const fileChange = () => {
var e = window.event || event
var oFile = e.target.files[0]
upLoadFilesHander(oFile).then((ress) => {
const { success, result } = ress
console.log(result)
})
const loading = ElLoading.service({
lock: true,
......@@ -105,53 +96,145 @@ const fileChange = () => {
})
loading.close()
}
const showWord = () => {
console.log(3)
}
// const loadFromBackend = async (value: string) => {
// try {
// //输入时候请求后端根据输入值得到提示。 后端返回集合,集合里面对象属性为value和link都是string类型
// const response = await axios.get(
// `http://localhost:8080/getAutoMsg/${value}`,
// )
// links.value = response.data
// } catch (error) {
// console.error(error)
// }
// }
const querySearchAsync = (queryString: string, cb: (arg: any) => void) => {
const results = queryString
? links.value.filter(createFilter(queryString))
: links.value
cb(results)
}
const createFilter = (queryString: string) => {
return (link: LinkItem) => {
return link.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
}
}
const handleSelect = (value: string) => {
console.log(value)
inputVal.value = value.target.innerHTML
}
const emit = defineEmits(['updateState'])
watch(state, async (newValue) => {
watch(inputVal, async (newValue) => {
if (!newValue) elAutocomplete.value.innerHTML = ''
emit('updateState', newValue)
})
// 去文本粘贴
const handlePaste = async (event) => {
event.preventDefault()
const pasteResult = handlePastePlainText(event.clipboardData)
if (pasteResult) return
await handlePasteImageFile(event.clipboardData)
}
// 去格式粘贴 文本
const handlePastePlainText = (clipboardData) => {
const text = clipboardData.getData('text/plain')
if (text) {
const textNode = document.createTextNode(text)
cursorInsert(textNode)
return true
}
return false
}
//改变光标位置
const cursorInsert = (node) => {
// 获取光标范围
const selObj = window.getSelection()
const range = selObj.getRangeAt(0)
// 光标处插入节点
range.insertNode(node)
// 取消insert node 后的选中状态,将光标恢复到 insert node 后面
range.collapse(false)
inputVal.value = elAutocomplete.value.innerHTML
}
//粘贴图片
const handlePasteImageFile = async (clipboardData) => {
const img = getPasteImageFile(clipboardData.files)
if (!img) {
return
}
const uploadRes = await fileToBase64(img)
if (!uploadRes) {
return
}
const oImage = await getImageObject(
uploadRes,
imgShowWidth.value,
imgShowHeight.value,
)
cursorInsert(oImage)
inputVal.value = elAutocomplete.value.innerHTML
}
// 获取一个 image object
const getImageObject = (uploadRes, showWidth, showHeight) => {
const oImage = new Image(showWidth, showHeight)
const datasetFields = ['width', 'height']
const datasetSizes = {
width: '200',
height: '200',
}
datasetFields.forEach((field) => {
oImage.setAttribute(`data-${field}`, datasetSizes[field])
})
oImage.src = uploadRes
return oImage
}
const getPasteImageFile = (clipboardDataFiles) => {
if (!clipboardDataFiles.length) {
return null
}
// 剪切版中选择的(用户第一个点的在尾)第一张图片
const clipboardDataFileList = Array.from(clipboardDataFiles || [])
let firstSelectedImage = null
clipboardDataFileList.forEach((file) => {
if (!file.type.match(/image\//i)) {
return
}
firstSelectedImage = file
})
return firstSelectedImage
}
//将文件流转base64
const fileToBase64 = function (file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = (event) => {
resolve(event.target.result)
}
reader.onerror = (error) => {
reject(error)
}
reader.readAsDataURL(file)
})
}
const removeDefaultContent = function (event) {
elAutocomplete.value.classList.remove('textarea')
cursorIn()
}
const addDefaultContent = function (event) {
if (!event.target.innerHTML && event.target.innerText.length == 0) {
elAutocomplete.value.classList.add('textarea')
}
}
const cursorIn = function () {
var divElement = document.querySelector('div[contenteditable="true"]')
var range = document.createRange()
range.selectNodeContents(divElement)
range.collapse(false)
var selection = window.getSelection()
selection.removeAllRanges()
selection.addRange(range)
}
defineExpose({
setState(res: any) {
state.value = res
inputVal.value = res
},
getState() {
return state.value
return inputVal.value
},
})
</script>
<style lang="scss" scoped>
.textarea {
&:after {
content: attr(placeholder);
display: inline-block;
color: #999;
font-size: 13px;
vertical-align: middle;
line-height: 16px;
}
}
.icon {
width: 24px;
height: 24px;
......@@ -165,17 +248,13 @@ defineExpose({
}
.el-autocomplete {
width: 100%;
height: 100%;
.el-input {
width: 100%;
}
:deep(.el-textarea__inner) {
width: 100%;
align-items: start;
box-shadow: none;
padding: 0px;
background: transparent;
}
max-width: 100%;
max-height: 150px;
overflow: auto;
}
.el-autocomplete img {
max-width: 100%; /* 设置图片最大宽度为容器宽度 */
max-height: 100%; /* 设置图片最大高度为容器高度 */
}
.chat-bar-right {
font-family: 'PingFang SC';
......
......@@ -4,21 +4,13 @@ import router from "./router";
import store from "./store/index";
import "./assets/css/reset.css";
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
import { initWebSocket } from "../src/utils/websocket";
import { useUserStore } from "./store/modules/user";
import 'element-plus/dist/index.css'
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");
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
const connectMsg = () => {
const useUser = useUserStore();
const toIp = `ws://192.168.31.228:8888?username=admin&password=123`;
console.log(useUser.isConnected, "store");
useUser.connect();
initWebSocket(toIp);
};
connectMsg();
const Mock = require('mockjs')
Mock.mock("/api/login", "get", () => {
Mock.mock("/kf/auth/login", "post", () => {
return {
code: "200",
success: true,
message: '',
result: {
userName: "admin",
username: "admin",
token: 'admin'
},
};
......@@ -17,7 +17,7 @@ Mock.mock("/api/inquiryAdd", "get", () => {
success: true,
message: '操作成功!',
result: {
userName: "admin",
username: "admin",
token: 'admin'
},
};
......@@ -49,12 +49,12 @@ Mock.mock("/api/getUserList", 'get', () => {
message: '',
result: [{
userId: '11fb824c0deb4e8b947275e1e7c4f7a2',
userName: '1710323861524',
username: '1710323861524',
userImg: 'https://cdn.lirimall.com//lirigo/filetempImage/新鲜水果_1661668973048.png',
messages: []
}, {
userId: '4f99b6dc32d84a288d88e7d9635521a3',
userName: '1710317951930',
username: '1710317951930',
userImg: 'https://cdn.lirimall.com//lirigo/filetempImage/新鲜水果_1661668973048.png',
messages: []
}]
......@@ -110,4 +110,14 @@ Mock.mock("/api/upload", 'get', () => {
},
},
}
})
Mock.mock("/deleteUserList",'delete',(req)=>{
console.log(req)
const id = Mock.mock.env.url.match(/\/(\d+)/)[1];
return {
code: '200',
success: true,
message: '删除成功!',
result: null,
}
})
\ No newline at end of file
//路由守卫.ts
import router from "../src/router";
import { useUserStore } from "./store/modules/user";
router.beforeEach((to: any, from: any, next: any) => {
const store = useUserStore();
const whiteList = ["/login", "/register"];
if (store.userInfo.token) {
next();
} else {
if (whiteList.includes(to.path)) {
//白名单登录
next();
} else {
next("/login");
}
}
});
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import HomeView from "../views/HomeView.vue";
const routes: Array<RouteRecordRaw> = [
{
path: "/",
......
......@@ -2,5 +2,6 @@ import { createPinia } from "pinia";
// 创建 Pinia 实例
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
const pinia = createPinia();
console.log(piniaPluginPersistedstate,'打印')
pinia.use(piniaPluginPersistedstate);
export default pinia;
......@@ -8,7 +8,9 @@ export const useUserStore = defineStore("user", {
customerInfo: {},
count: 0,
userInfo: {
userName: "admin",
username: "admin",
password:"",
token:""
},
userList: [],
};
......@@ -24,42 +26,39 @@ export const useUserStore = defineStore("user", {
this.userInfo = res;
},
setUserList(res: any) {
console.log(res,'数据呢')
this.userList = res;
},
setUserListMessages(res: any) {
console.log(res)
const userList: any = this.userList || [];
// res.from = res.from.replace('游客','')
const obj = {
...res,
isSent: false,
msgType: res.msgType,
content: res.content,
cmd: res.cmd,
to: res.to,
id: res.id,
form: res.from,
userImg:
"https://cdn.lirimall.com//lirigo/filetempImage/新鲜水果_1661668973048.png",
time: moment(res.createTime).format("YYYY-DD-MM HH:mm:ss"),
};
const info = {
userId: res.id,
userName: res.from,
username: res.from,
messages: [obj],
userImg: obj.userImg,
};
if (
userList.length > 0 &&
userList.some((item: any) => item.userName == res.from)
userList.some((item: any) => item.username == res.from)
) {
userList.forEach((item: any) => {
if (item.userName == res.from) item.messages.push(obj);
if (item.username == res.from) item.messages.push(obj);
});
} else {
userList.push(info);
}
this.userList = userList;
},
setUserNameMessage(res: any) {
setusernameMessage(res: any) {
const friends = res.friends;
for (const key in friends) {
const chatDatas = friends[key];
......@@ -71,7 +70,7 @@ export const useUserStore = defineStore("user", {
for (const index in chatDatas) {
const userId = chatDatas[index].from;
this.userList.forEach((item: any) => {
if (item && item?.userName == userId) {
if (item && item?.username == userId) {
item.messages = chatDatas;
}
});
......
export interface LoginFace {
userName: string;
passWord: string;
username: string;
password: string;
}
export class LoginData<LoginFace> {
userName = "admin";
passWord = "123456";
username = "10086";
password = "123456";
}
......@@ -64,14 +64,14 @@ function websocketOpen() {
}
// 数据接收
function websocketonmessage(e: MessageEvent<any>) {
console.log('接受数据',e.data)
const res = JSON.parse(e.data); // 解析JSON格式的数据
console.log(res, "发送一次");
// 下面的判断则是后台返回的接收到的数据 如何处理自己决定
if (res.command == 11) {
//将数据放在store中
useUserStore().setUserListMessages(res.data);
} else if (res.command == 20) {
useUserStore().setUserNameMessage(res.data);
useUserStore().setusernameMessage(res.data);
}
}
......
......@@ -25,9 +25,9 @@
<div class="user-info-right">
<div class="user-box-right-nbs">
<div class="user-name-box">
<span class="user-name">{{ item?.userName }}</span>
<span class="user-name">{{ item?.username }}</span>
<div class="user-time">
05-19 16:38
{{ item?.time }}
</div>
</div>
<div class="user-reply-box">
......@@ -35,8 +35,8 @@
{{
item?.messages[
item?.messages.length - 1
]?.content.includes('http')
? '[图]'
]?.content.includes('img')
? '[图]'
: item.messages[item.messages.length - 1]?.content
}}
</span>
......@@ -48,9 +48,9 @@
</div>
</div>
</el-aside>
<el-container class="el-container-center" v-if="customerInfo.userName">
<el-container class="el-container-center" v-if="customerInfo.username">
<el-header class="el-header-center">
<p class="name">{{ customerInfo.userName }}</p>
<p class="name">{{ customerInfo.username }}</p>
<p class="url">US|https://www.ibeautytop.com</p>
</el-header>
<el-main
......@@ -71,12 +71,10 @@
<div class="time">{{ message.time }}</div>
<div v-if="message.isSent" class="message-container">
<div class="bubble">
<div
v-if="message?.msgType == 0"
class="message"
v-html="message?.content"
@click.prevent="handleMessageClick($event)"
></div>
<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"
......@@ -97,12 +95,10 @@
<img :src="message?.userImg" class="avatar-image" />
</div>
<div class="bubble">
<div
v-if="message?.msgType == 0"
class="message"
v-html="message?.content"
@click.prevent="handleMessageClick($event)"
></div>
<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"
......@@ -254,13 +250,21 @@ import AutomaticPrompt from '../components/AutomaticPrompt.vue'
import ImageViewer from '@luohc92/vue3-image-viewer'
import { sendWebSocket } from '../utils/websocket'
import type { FormInstance } from 'element-plus'
import { initWebSocket } from '../utils/websocket'
import '@luohc92/vue3-image-viewer/dist/style.css'
import { getUserList, InquiryAdd, checkMesssages } from '../axios/model/user'
const ruleForm = ref({
count: 1,
})
const connectMsg = () => {
const useUser = useUserStore()
const toIp = `ws://192.168.31.228:8081?type=kf&code=${useUser.userInfo?.username}`
console.log(toIp)
useUser.connect()
initWebSocket(toIp)
}
connectMsg()
const ruleFormRef = ref<FormInstance>()
const customerInfo = ref({})
const messages = ref([])
......@@ -321,16 +325,17 @@ let msg = ''
//进入页面直接发送请求从后端获取热点数据
onMounted(async () => {
count.value = store.count
if (store.userList.length > 0) {
userList.value = store.userList
} else {
getList()
}
// if (store.userList.length > 0) {
// userList.value = store.userList
// } else {
// getList()
// }
userList.value = store.userList
setMessage()
})
//设置message
const setMessage = () => {
if (store.customerInfo.userName) {
if (store.customerInfo.username) {
customerInfo.value = store.customerInfo
messages.value = customerInfo.value.messages || []
}
......@@ -348,7 +353,7 @@ const getList = async () => {
})
userList.value = list
store.setUserList(list)
if (customerInfo.value.userName) handleMenuClick(customerInfo.value)
if (customerInfo.value.username) handleMenuClick(customerInfo.value)
}
} catch (error) {
console.log(error)
......@@ -366,10 +371,10 @@ const handleChange = (val: any) => {
watch(
userList,
(newVal, oldVal) => {
if (newVal && newVal.length > 0 && customerInfo.value.userName) {
if (newVal && newVal.length > 0 && customerInfo.value.username) {
const obj =
newVal.find((item: any) => {
return item.userName == customerInfo.value.userName
return item.username == customerInfo.value.username
}) || {}
messages.value = obj.messages || []
}
......@@ -400,28 +405,37 @@ const handleMenuClick = (item: object) => {
const data = {
cmd: '19',
type: '1',
fromUserId: item?.userName,
fromUserId: item?.username,
group_id: '',
userId: store.userInfo.userName,
userId: store.userInfo.username,
}
sendWebSocket(data)
getCheckMesssages(data)
}
//发送按钮
const handleButtonClick = () => {
if (!msg) {
return ElMessage({
message: '请输入内容',
type: 'error',
})
}
let data = {
content: msg,
contentFy: msg,
isSent: true,
cmd: '11',
msgType: 0,
fromLang: 'cn',
toLang: 'en',
chatType: '2',
group_id: '',
time: getShortDate(),
to: customerInfo.value.userName,
form: store.userInfo.userName,
to: customerInfo.value.username,
form: store.userInfo.username,
}
messages.value?.push(data)
console.log('打印客户发送的内容', data)
sendWebSocket(data)
automaticPromptRef.value.setState('')
}
......@@ -460,7 +474,7 @@ const handleMessageClick = (event: any) => {
const getCheckMesssages = async (res: any) => {
try {
const { success, result, message }: any = await checkMesssages({
userName: res.userName,
username: res.username,
})
} catch (error) {
console.log(error)
......@@ -498,7 +512,7 @@ const getMessageClass = (isSent: boolean) => {
}
//左边按钮操作
const getMenuItem = (item: any) => {
return item.userName == customerInfo.value?.userName ? 'is-active' : ''
return item.username == customerInfo.value?.username ? 'is-active' : ''
}
</script>
<style lang="scss" scoped>
......@@ -523,7 +537,7 @@ const getMenuItem = (item: any) => {
}
}
.el-container-center {
background: #e6e8ed;
background: #F8F8FA;
}
.el-header-center {
height: 76px;
......@@ -831,7 +845,7 @@ const getMenuItem = (item: any) => {
.bubble {
background-color: #e8e8e8;
color: #000;
padding: 10px;
padding: 10px 14px;
border-radius: 5px;
max-width: 320px;
background: #f5f5f5;
......@@ -849,14 +863,38 @@ const getMenuItem = (item: any) => {
.message {
text-align: left;
margin: 0;
.content {
font-family: 'Inter';
font-size: 16px;
font-style: normal;
font-weight: 400;
color: #0c203d;
}
.contentFy {
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
color: #798494;
line-height: 20px;
}
}
.message-container-right {
justify-content: flex-end;
.bubble{
background: #E6E8EB;
border-radius: 8px 0 8px 8px;
}
}
.message-container-left {
justify-content: flex-start;
.bubble{
background: #FFFFFF;
border-radius: 0px 8px 8px 8px;
margin-left: 8px;
}
}
.avatar-number-input :deep(.el-input) {
width: 102px !important;
......
......@@ -9,17 +9,17 @@
class="form-box"
>
<h2>客服登录</h2>
<el-form-item label="账号" prop="userName" size="large">
<el-form-item label="账号" prop="username" size="large">
<el-input
v-model="ruleForm.userName"
type="userName"
v-model="ruleForm.username"
type="username"
placeholder="请输入账号"
autocomplete="off"
/>
</el-form-item>
<el-form-item label="密码" prop="passWord" size="large">
<el-form-item label="密码" prop="password" size="large">
<el-input
v-model="ruleForm.passWord"
v-model="ruleForm.password"
type="password"
autocomplete="off"
placeholder="请输入密码"
......@@ -46,7 +46,9 @@ import { LoginData } from '../type/Login'
import { reactive, ref } from 'vue'
import { useUserStore } from '../store/modules/user'
import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import axios from 'axios'
import { Login } from '../axios/model/user'
export default {
setup() {
......@@ -55,14 +57,14 @@ export default {
const store = useUserStore()
const router = useRouter()
const rules = reactive({
userName: [
username: [
{
required: true,
message: '请输入账号',
trigger: 'blur',
},
],
passWord: [
password: [
{
required: true,
message: '请输入密码',
......@@ -72,22 +74,51 @@ export default {
})
//重置
const resetForm = (formEl: FormInstance | undefined) => {
ruleForm.userName = ''
ruleForm.passWord = ''
ruleForm.username = ''
ruleForm.password = ''
if (!formEl) return
formEl.resetFields()
}
//登录
//登录
const deleteList1 = () => {
let data = {
id: '111',
}
// deleteUserList(data).then((res: any) => {
// console.log(res)
// ElMessage({
// message: '请输入内容',
// type: 'error',
// })
// console.log(res)
// })
// axios
// .delete('/api/getUserList/' + data.id)
// .then((response) => {
// console.log(response.data)
// })
// .catch((error) => {
// console.error(error)
// })
}
const submitForm = (formEl: FormInstance | undefined) => {
let query = {}
if (!formEl) return
formEl.validate((valid: boolean) => {
if (valid) {
Login(query).then(({ success, message,result }: any) => {
let data = {
username: ruleForm.username,
password: ruleForm.password,
}
Login(data).then(({ success, message, result }: any) => {
if (success) {
router.push('/')
store.setUserInfo(result)
store.setUserInfo({
...result.userInfo,
token: result.token,
})
}
})
} else {
......@@ -95,7 +126,7 @@ export default {
}
})
}
deleteList1()
return { ruleForm, ruleFormRef, rules, resetForm, submitForm }
},
}
......
const { defineConfig } = require('@vue/cli-service')
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = defineConfig({
transpileDependencies: true,
......@@ -14,4 +15,9 @@ module.exports = defineConfig({
}),
],
},
// chainWebpack: config => {
// config.plugin('html').use(HtmlWebpackPlugin, [{
// title:'客服端',
// }])
// }
})
\ No newline at end of file
......@@ -4036,6 +4036,17 @@ html-webpack-plugin@^5.1.0:
pretty-error "^4.0.0"
tapable "^2.0.0"
html-webpack-plugin@^5.6.0:
version "5.6.0"
resolved "https://registry.npmmirror.com/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz#50a8fa6709245608cb00e811eacecb8e0d7b7ea0"
integrity sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==
dependencies:
"@types/html-minifier-terser" "^6.0.0"
html-minifier-terser "^6.0.2"
lodash "^4.17.21"
pretty-error "^4.0.0"
tapable "^2.0.0"
htmlparser2@^6.1.0:
version "6.1.0"
resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-6.1.0.tgz"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论