This commit is contained in:
许gitee 2025-02-20 12:50:57 +08:00
parent 5a07571cfe
commit ef1e3179be
20 changed files with 1550 additions and 266 deletions

214
package-lock.json generated
View File

@ -15,6 +15,8 @@
"core-js": "^3.8.3",
"echarts": "^5.5.1",
"element-plus": "^2.8.3",
"marked": "^15.0.6",
"openai": "^4.83.0",
"sass": "^1.79.2",
"sass-loader": "^16.0.1",
"svg-sprite-loader": "^6.0.11",
@ -2378,11 +2380,19 @@
"version": "22.5.5",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.5.5.tgz",
"integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
"devOptional": true,
"dependencies": {
"undici-types": "~6.19.2"
}
},
"node_modules/@types/node-fetch": {
"version": "2.6.12",
"resolved": "https://registry.npmmirror.com/@types/node-fetch/-/node-fetch-2.6.12.tgz",
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
"dependencies": {
"@types/node": "*",
"form-data": "^4.0.0"
}
},
"node_modules/@types/node-forge": {
"version": "1.3.11",
"resolved": "https://registry.npmmirror.com/@types/node-forge/-/node-forge-1.3.11.tgz",
@ -3372,6 +3382,17 @@
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"devOptional": true
},
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz",
@ -3427,6 +3448,17 @@
"node": ">= 10.0.0"
}
},
"node_modules/agentkeepalive": {
"version": "4.6.0",
"resolved": "https://registry.npmmirror.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
"integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==",
"dependencies": {
"humanize-ms": "^1.2.1"
},
"engines": {
"node": ">= 8.0.0"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
@ -5969,6 +6001,14 @@
"node": ">=4.0.0"
}
},
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"engines": {
"node": ">=6"
}
},
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz",
@ -6352,6 +6392,23 @@
"node": ">= 6"
}
},
"node_modules/form-data-encoder": {
"version": "1.7.2",
"resolved": "https://registry.npmmirror.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
"integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="
},
"node_modules/formdata-node": {
"version": "4.4.1",
"resolved": "https://registry.npmmirror.com/formdata-node/-/formdata-node-4.4.1.tgz",
"integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
"dependencies": {
"node-domexception": "1.0.0",
"web-streams-polyfill": "4.0.0-beta.3"
},
"engines": {
"node": ">= 12.20"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz",
@ -7074,6 +7131,14 @@
"node": ">=10.17.0"
}
},
"node_modules/humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npmmirror.com/humanize-ms/-/humanize-ms-1.2.1.tgz",
"integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
"dependencies": {
"ms": "^2.0.0"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -8164,6 +8229,17 @@
"node": ">=0.10.0"
}
},
"node_modules/marked": {
"version": "15.0.6",
"resolved": "https://registry.npmmirror.com/marked/-/marked-15.0.6.tgz",
"integrity": "sha512-Y07CUOE+HQXbVDCGl3LXggqJDbXDP2pArc2C1N1RRMN0ONiShoSsIInMd5Gsxupe7fKLpgimTV+HOJ9r7bA+pg==",
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/mdn-data": {
"version": "2.0.14",
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz",
@ -8485,8 +8561,7 @@
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/multicast-dns": {
"version": "7.2.5",
@ -8615,11 +8690,28 @@
"tslib": "^2.0.3"
}
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dev": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
@ -8911,6 +9003,48 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/openai": {
"version": "4.83.0",
"resolved": "https://registry.npmmirror.com/openai/-/openai-4.83.0.tgz",
"integrity": "sha512-fmTsqud0uTtRKsPC7L8Lu55dkaTwYucqncDHzVvO64DKOpNTuiYwjbR/nVgpapXuYy8xSnhQQPUm+3jQaxICgw==",
"dependencies": {
"@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4",
"abort-controller": "^3.0.0",
"agentkeepalive": "^4.2.1",
"form-data-encoder": "1.7.2",
"formdata-node": "^4.3.2",
"node-fetch": "^2.6.7"
},
"bin": {
"openai": "bin/cli"
},
"peerDependencies": {
"ws": "^8.18.0",
"zod": "^3.23.8"
},
"peerDependenciesMeta": {
"ws": {
"optional": true
},
"zod": {
"optional": true
}
}
},
"node_modules/openai/node_modules/@types/node": {
"version": "18.19.75",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.19.75.tgz",
"integrity": "sha512-UIksWtThob6ZVSyxcOqCLOUNg/dyO1Qvx4McgeuhrEtHTLFTf7BBhEazaE4K806FGTPtzd/2sE90qn4fVr7cyw==",
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/openai/node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
},
"node_modules/opener": {
"version": "1.5.2",
"resolved": "https://registry.npmmirror.com/opener/-/opener-1.5.2.tgz",
@ -12034,8 +12168,7 @@
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"dev": true
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/traverse": {
"version": "0.6.10",
@ -12186,8 +12319,7 @@
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"devOptional": true
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
},
"node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.1",
@ -12635,11 +12767,18 @@
"defaults": "^1.0.3"
}
},
"node_modules/web-streams-polyfill": {
"version": "4.0.0-beta.3",
"resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
"integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
"engines": {
"node": ">= 14"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"dev": true
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/webpack": {
"version": "5.94.0",
@ -12734,6 +12873,27 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/webpack-bundle-analyzer/node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmmirror.com/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"dev": true,
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/webpack-chain": {
"version": "6.5.1",
"resolved": "https://registry.npmmirror.com/webpack-chain/-/webpack-chain-6.5.1.tgz",
@ -12936,27 +13096,6 @@
"url": "https://opencollective.com/webpack"
}
},
"node_modules/webpack-dev-server/node_modules/ws": {
"version": "8.18.0",
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"dev": true,
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/webpack-merge": {
"version": "5.10.0",
"resolved": "https://registry.npmmirror.com/webpack-merge/-/webpack-merge-5.10.0.tgz",
@ -13037,7 +13176,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dev": true,
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
@ -13151,16 +13289,16 @@
"dev": true
},
"node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmmirror.com/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"dev": true,
"version": "8.18.0",
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"devOptional": true,
"engines": {
"node": ">=8.3.0"
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {

View File

@ -14,6 +14,8 @@
"core-js": "^3.8.3",
"echarts": "^5.5.1",
"element-plus": "^2.8.3",
"marked": "^15.0.6",
"openai": "^4.83.0",
"sass": "^1.79.2",
"sass-loader": "^16.0.1",
"svg-sprite-loader": "^6.0.11",

View File

@ -1,4 +1,4 @@
import { createApp } from 'vue'
import {createApp, ref} from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
@ -14,4 +14,18 @@ axios.defaults.withCredentials=true
// 意思是携带cookie信息,保持session的一致性
createApp(App).use(store).use(router).use(ElementPlus).use(SvgIcon).mount('#app');
const editableTabs = ref([
{
title: '首页',
name: 'home'
}
])
const editableTabsValue = ref('')
// 挂载到全局属性
const app=createApp(App);
app.config.globalProperties.$editableTabs = editableTabs;
app.config.globalProperties.$editableTabsValue = editableTabsValue;
app.use(store).use(router).use(ElementPlus).use(SvgIcon).mount('#app');

View File

@ -75,6 +75,21 @@ const routes = [
name: '审核美甲师',
component: () => import('../views/employee/verify/index.vue'),
},
{
path: '/nocontractemployee',
name: '未签约美甲师',
component: () => import('../views/employee/NoContract/index.vue'),
},
{
path: '/ai',
name: 'AI',
component: () => import('../views/AI/index.vue'),
},
{
path: '/contractemployee',
name: '签约美甲师',
component: () => import('../views/employee/contract/index.vue'),
},
{
path: '/qiangdan',
name: '抢单',
@ -91,8 +106,13 @@ const routes = [
component: () => import('../views/order/index')
},
{
path: '/orderReservation',
path: '/userReservation',
name: '上门预约',
component: () => import('../views/order/useRreservation/index.vue')
},
{
path: '/orderReservation',
name: '个人预约详情',
component: () => import('../views/order/reservation/index.vue')
},
{

View File

@ -3,8 +3,8 @@ import axios from 'axios';
// let baseUrl='http://localhost:8081/api/';
let baseUrl='http://154.8.193.216:1107/api/';
let baseUrl='http://localhost:8081/api/';
let baseUrl2='http://154.8.193.216:1107/api/';
// 创建axios实例
const httpService = axios.create({
// url前缀-'http:xxx.xxx'
@ -98,10 +98,14 @@ export function fileUpload(url, params = {}) {
export function getServerUrl(){
return baseUrl;
}
export function getServerUrl2(){
return baseUrl2;
}
export default {
get,
post,
fileUpload,
getServerUrl
getServerUrl,
getServerUrl2
}

104
src/util/marked.js Normal file
View File

@ -0,0 +1,104 @@
import {marked} from 'marked';
const parseMarkdown = (content) => {
return marked.parse(content) // 使用 marked 解析 Markdown
}
const menua=[
{
path: 'home',
name: '首页',
},
{
path: 'user',
name: '用户管理',
},
{
path: 'business',
name: '商家列表',
},
{
path: 'businesVerify',
name: '审核商家入驻',
},
{
path: 'businessProduct',
name: '商家商品',
},
{
path: 'product',
name: '商品列表',
},
{
path: 'productCategory',
name: '商品分类',
},
{
path: 'message',
name: '消息通知',
},
{
path: 'permission',
name: '星级评优',
},
{
path: 'employee',
name: '美甲师列表',
},
{
path: 'employeeVerify',
name: '审核美甲师认证',
},
{
path: 'nocontractemployee',
name: '未签约美甲师',
},
{
path: 'contractemployee',
name: '签约美甲师',
},
{
path: 'qiangdan',
name: '抢单',
},
{
path: 'modifyPassword',
name: '修改密码',
},
{
path: 'order',
name: '订单列表',
},
{
path: 'userReservation',
name: '上门预约',
},
{
path: 'orderReservation',
name: '到店服务',
},
{
path: 'personal',
name: '个人中心',
},
{
path: 'rating',
name: '评价操作',
},
{
path: 'profile',
name: '详情',
}]
export function getMenu(temp){
const t=menua.filter(tab=>tab.path==temp)
return t[0].name
}

View File

@ -29,4 +29,11 @@ export function verifyPerson(){
return false;
}
//console.log(ax.value)
}
export function getBusinessID(){
let JS=window.sessionStorage.getItem("BUSINESS_STATE");
const id=JSON.parse(JS).id
return id;
}

269
src/views/AI/index.vue Normal file
View File

@ -0,0 +1,269 @@
<template>
欢迎使用DeepSeek的拓展AI
<div class="chat-container" >
<!-- 消息展示区域 -->
<div class="message-list" ref="messageContainer">
<div
v-for="(message, index) in messages"
:key="index"
class="message-item"
:class="[message.sender]"
>
<div class="avatar" style="margin-right: 10px" v-if="message.sender=='admin'">
<img :src="message.avatar" />
</div>
<div class="message-bubble" >
<div class="message-content" v-html="parseMarkdown(message.content)"></div>
<div class="message-time">{{ formatTime(message.timestamp) }}</div>
</div>
<div class="avatar" style="margin-left: 10px" v-if="message.sender=='user'">
<img :src="message.avatar" />
</div>
</div>
</div>
<!-- 消息输入区域 -->
<div class="input-area">
<input
v-model="newMessage"
type="text"
placeholder="输入消息..."
@keyup.enter="sendMessage"
/>
<button @click="sendMessage">发送</button>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick, computed } from 'vue'
import {OpenAI} from "openai";
import { marked } from 'marked'
import {ElLoading} from "element-plus"; // marked
const loading=ref(false)
const parseMarkdown = (content) => {
return marked.parse(content) // 使 marked Markdown
}
const avatar1=ref( 'https://wx4.sinaimg.cn/mw690/005ZDPezgy1hw85hfnk2sj30w50u0q7q.jpg') //
const avatar2=ref( 'https://ww1.sinaimg.cn/mw690/0089PUyVly1hvw18p2uo4j30sg0stn0w.jpg') //
//
const messages = reactive([
{
content: '您好,有什么可以帮您?',
sender: 'admin',
avatar: avatar1,
timestamp: new Date()
}
])
const newMessage = ref('')
const messageContainer = ref(null)
//
const sendMessage = () => {
if (!newMessage.value.trim()) return
//
messages.push({
content: newMessage.value,
sender: 'user',
avatar: avatar2,
timestamp: new Date()
})
ai(newMessage.value)
setTimeout(() => {
openFullScreen(true)
//AI
}, 500)
// 1
// setTimeout(() => {
// messages.push({
// content: '',
// sender: 'admin',
// timestamp: new Date()
// })
// scrollToBottom()
// }, 1000)
// scrollToBottom()
newMessage.value = ''
scrollToBottom()
}
const openai = new OpenAI({
baseURL: 'https://api.deepseek.com',
apiKey: 'sk-d06e4f2cbe4342bdb2e2c8e0d12a5c25',
dangerouslyAllowBrowser: true
});
const ai =async(temp)=>{
console.log(JSON.stringify(temp))
const completion = await openai.chat.completions.create({
messages: [{ role: "system", content: JSON.stringify(temp) }],
model: "deepseek-chat",
});
console.log(completion.choices[0].message.content);
messages.push({
content: completion.choices[0].message.content,
sender: 'admin',
avatar: avatar1,
timestamp: new Date()
})
openFullScreen(false)
}
//
const formatTime = (date) => {
return date.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit'
})
}
const openFullScreen = (temp) => {
const loading = ElLoading.service({
lock: true,
text: '加载中,可能等待较长时间...',
background: 'rgba(0, 0, 0, 0.7)',
})
if (!temp){
loading.close()
}
}
//
const scrollToBottom = () => {
nextTick(() => {
if (messageContainer.value) {
messageContainer.value.scrollTop = messageContainer.value.scrollHeight
}
})
}
</script>
<style scoped>
.chat-container {
width: 100%;
margin: 20px auto;
border: 1px solid #e0e0e0;
border-radius: 8px;
overflow: hidden;
background: #f5f5f5;
}
.message-list {
height: 400px;
padding: 20px;
overflow-y: auto;
}
.message-item {
display: flex;
margin-bottom: 15px;
}
.message-item.user {
justify-content: flex-end;
}
.message-item.user avatar {
order: 2; /* 用户头像在右侧 */
margin-left: 10px;
}
.message-item.user .message-bubble {
background: #67c23a;
color: white;
border-bottom-right-radius: 4px;
}
.message-item.admin avatar {
order: 1; /* 管理员头像在左侧 */
margin-right: 10px;
}
.message-item.admin .message-bubble {
background: white;
border: 1px solid #e0e0e0;
border-bottom-left-radius: 4px;
}
.avatar img {
width: 50px;
height: 50px;
border-radius: 50%;
}
.message-bubble {
max-width: 70%;
padding: 12px 16px;
border-radius: 12px;
position: relative;
}
.message-content {
word-break: break-word;
}
.message-content >>> pre {
background: #f5f5f5;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
}
.message-content >>> code {
font-family: 'Courier New', Courier, monospace;
background: #f5f5f5;
padding: 2px 4px;
border-radius: 2px;
}
.message-time {
font-size: 12px;
color: #666;
margin-top: 4px;
text-align: right;
}
.input-area {
display: flex;
padding: 20px;
background: white;
border-top: 1px solid #eee;
}
.input-area input {
flex: 1;
padding: 10px;
border: 1px solid #e0e0e0;
border-radius: 4px;
margin-right: 10px;
}
.input-area button {
padding: 10px 20px;
background: #409eff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.input-area button:hover {
background: #66b1ff;
}
</style>

View File

@ -114,8 +114,8 @@ const handleConfirm=async()=>{
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
width: 50px;
height: 50px;
display: block;
}
</style>

View File

@ -0,0 +1,223 @@
<template>
<el-card>
<el-row :gutter="20" class="header">
<el-col :span="7">
<el-input placeholder="请输入美甲师ID..." clearable v-model="query" ></el-input>
</el-col>
<el-button type="button" :icon="Search" @click="initEmployeeList">搜索</el-button>
</el-row>
<el-table :data="tempData" stripe style="width: 100%;" showOverflowTooltip>
<el-table-column prop="id" label="#ID" width="80" />
<el-table-column prop="manicuristName" label="用户昵称" width="200" />
<el-table-column prop="manicuristAvatar" label="头像" width="200">
<template v-slot="scope">
<img :src="scope.row.manicuristAvatar" width="50" height="50"/>
</template>
</el-table-column>
<el-table-column label="性别" prop="gender">
<template #default="scope">
<div v-if="scope.row.gender==0"></div>
<div v-else></div>
</template>
</el-table-column>
<el-table-column label="商家" prop="businessId"/>
<el-table-column label="签约状态" prop="businessId">
<template #default="scope">
<div v-if="scope.row.businessId>0">已签约</div>
<div v-else style="color: red">未签约</div>
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" width="120px"/>
<el-table-column prop="email" label="邮箱" width="180px"/>
<el-table-column prop="rating" label="评分" width="200px">
<template v-slot="scope" style="height: 100px">
<div class="demo-rate-block">
<el-rate v-model="scope.row.rating" :colors="colors"/>
{{scope.row.rating}}
</div>
</template>
</el-table-column>
<el-table-column prop="createTime" label="注册日期" width="200"/>
<el-table-column prop="updateTime" label="最后登录日期" width="200"/>
<el-table-column prop="action" fixed="right" label="操作" min-width="120">
<template v-slot="scope" >
<!-- <el-button @click="handleRouter(scope.row.id)" type="primary" :icon="DocumentAdd" >审核美甲师</el-button>-->
<!-- <el-button type="success" size="small" @click="handleDialogValue(scope.row.id)">-->
<!-- 详情-->
<!-- </el-button>-->
<!-- <el-button type="primary" size="small" :icon="Edit" @click="handleUpdateDialogValue(scope.row.id)"></el-button>-->
<el-button type="danger" size="small" :icon="Delete" @click="handleMessage(scope.row.id)">签约</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:currentPage="queryForm.current"
layout="total, prev, pager, next, jumper"
:total="total"
@current-change="handleCurrentChange"
/>
</el-card>
</template>
<script setup>
import {Search,DocumentAdd,Delete,Edit} from '@element-plus/icons-vue'
import {ref, watch} from 'vue'
import axios from "@/util/axios";
import {getBusinessID} from "@/util/time";
import { ElMessage,ElMessageBox } from "element-plus";
const queryForm=ref({
current:1,
pageSize:10
})
const query=ref();
const total=ref(0)
const tableData =ref([])
const qianButton=ref({
businessId: "",
id: ""
})
const handleMessage=(ids)=>{
// console.log(ids)
ElMessageBox.confirm(
'您确定要签约这个美甲师吗?',
'系统提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(async() => {
qianButton.value.id=ids;
qianButton.value.businessId=getBusinessID()
let res=await axios.post("manicurist/update",qianButton.value)
if(res.data.code==0){
ElMessage({
type: 'success',
message: '签约成功',
})
initEmployeeList();
}else{
ElMessage({
type: 'error',
message: res.data.description,
})
}
})
.catch(() => {
})
}
const tempData=ref([])
const tempstore=()=>{
tempData.value.slice(0,0)
tempData.value=tableData.value.slice(0,10)
}
const initEmployeeList=async()=>{
if (!query.value){
const res=await axios.post("manicurist/queryAll");
// console.log(res.data)
tableData.value=res.data.data;
tableData.value.filter(item=>item.auditStatus==1)
const t=[]
tableData.value.filter(item=>{
if(item.businessId==0||item.businessId==null){
t.push(item)
}
})
tableData.value=t
total.value=Number(tableData.value.length);
tempstore()
}else{
// const res = await axios.get("manicurist/queryById", {manicuristId: query.value});
// console.log(res.data)
const temp=tableData.value.filter(item=>item.id==query.value)
console.log(temp)
// temp.push(res.data.data)
tableData.value = temp;
total.value = 1;
tempstore()
}
}
initEmployeeList();
const handleSizeChange = (pageSize) => {
queryForm.value.current=1;
queryForm.value.pageSize=pageSize;
initEmployeeList();
}
const handleCurrentChange = (pageNum) => {
tempData.value=tableData.value.slice(pageNum*10-10,pageNum*10)
}
// =============================================
const colors = ref(['#99A9BF', '#F7BA2A', '#FF9900'])
</script>
<style lang="scss" scoped>
.header{
padding-bottom: 16px;
box-sizing: border-box;
}
.el-pagination{
padding-top: 15px;
box-sizing: border-box;
}
.demo-rate-block {
padding: 15px 0;
text-align: center;
border-right: solid 1px var(--el-border-color);
display: inline-block;
width: 49%;
box-sizing: border-box;
}
.demo-rate-block:last-child {
border-right: none;
}
.demo-rate-block .demonstration {
display: block;
color: var(--el-text-color-secondary);
font-size: 14px;
margin-bottom: 20px;
}
</style>

View File

@ -0,0 +1,293 @@
<template>
<el-card>
<el-row :gutter="20" class="header">
<el-col :span="7">
<el-input placeholder="请输入美甲师ID..." clearable v-model="query" ></el-input>
</el-col>
<el-button type="button" :icon="Search" @click="initEmployeeList">搜索</el-button>
</el-row>
<el-table :data="tempData" stripe style="width: 100%;" showOverflowTooltip>
<el-table-column prop="id" label="#ID" width="80" />
<el-table-column prop="manicuristName" label="用户昵称" width="200" />
<el-table-column prop="manicuristAvatar" label="头像" width="200">
<template v-slot="scope">
<img :src="scope.row.manicuristAvatar" width="50" height="50"/>
</template>
</el-table-column>
<el-table-column label="性别" prop="gender">
<template #default="scope">
<div v-if="scope.row.gender==0"></div>
<div v-else></div>
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" width="120px"/>
<el-table-column prop="email" label="邮箱" width="180px"/>
<el-table-column prop="rating" label="评分" width="200px">
<template v-slot="scope" style="height: 100px">
<div class="demo-rate-block">
<el-rate v-model="scope.row.rating" :colors="colors"/>
{{scope.row.rating}}
</div>
</template>
</el-table-column>
<el-table-column prop="salary" label="余额" />
<el-table-column prop="manStatus" label="状态" >
<template v-slot="scope">
<el-switch
v-model="scope.row.manStatus"
@change="updateSwtich(scope.row)"
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
/>
</template>
</el-table-column>
<el-table-column prop="createTime" label="注册日期" width="200"/>
<el-table-column prop="updateTime" label="最后登录日期" width="200"/>
<el-table-column prop="action" fixed="right" label="操作" min-width="220">
<template v-slot="scope" >
<!-- <el-button @click="handleRouter(scope.row.id)" type="primary" :icon="DocumentAdd" >审核美甲师</el-button>-->
<el-button type="success" size="small" @click="handleDialogValue(scope.row.id)">
详情
</el-button>
<el-button type="primary" size="small" :icon="Edit" @click="handleUpdateDialogValue(scope.row.id)"></el-button>
<el-button type="danger" size="small" :icon="Delete" @click="handleDelete(scope.row.id)"></el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:currentPage="queryForm.current"
layout="total, prev, pager, next, jumper"
:total="total"
@current-change="handleCurrentChange"
/>
</el-card>
<Dialog v-model="edialogVisible" :id="id" :dialogTitle="dialogTitle"
@initEmployeeList="initEmployeeList"></Dialog>
<UpdateDialog v-model="edialogUpdateVisible" :id="id" :dialogTitle="dialogTitle"
@initEmployeeList="initEmployeeList"></UpdateDialog>
</template>
<script setup>
import {Search,DocumentAdd,Delete,Edit} from '@element-plus/icons-vue'
import {ref, watch} from 'vue'
import axios from "@/util/axios";
import Dialog from '@/views/employee/dialog/index.vue'
import {getBusinessID} from "@/util/time";
import UpdateDialog from '@/views/employee/updateDialog/index.vue'
import { ElMessage,ElMessageBox } from "element-plus";
const queryForm=ref({
current:1,
pageSize:10
})
const query=ref();
const total=ref(0)
const tableData =ref([])
const id=ref('')
const dialogTitle=ref('');
const edialogaddVisible=ref(false)
const edialogVisible=ref(false)
const edialogUpdateVisible=ref(false)
const tempUpdate=ref({
id: null,
phone: "",
manicuristName: "",
userStatus: null
})
const updateSwtich= async (item)=>{
tempUpdate.value.id=item.id
tempUpdate.value.phone=item.phone
tempUpdate.value.manicuristName=item.manicuristName
if (item.manStatus==false){
tempUpdate.value.manStatus=1
}
else {
tempUpdate.value.manStatus=0
}
//console.log("1341234"+JSON.stringify(tempUpdate.value))
let result = await axios.post("manicurist/update", tempUpdate.value)
//console.log(result.data)
}
const handleDialogValue=(ids)=>{
id.value=ids;
dialogTitle.value="美甲师详情"
edialogVisible.value=true
}
const handleUpdateDialogValue=(ids)=>{
// console.log(id)
id.value=ids;
// console.log(id.value)
dialogTitle.value="美甲师修改"
edialogUpdateVisible.value=true
}
const handleDelete=(ids)=>{
// console.log(ids)
ElMessageBox.confirm(
'您确定要删除这条记录吗?',
'系统提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(async() => {
let res=await axios.post('manicurist/deleteMan?id='+Number(ids))
if(res.data.code==0){
ElMessage({
type: 'success',
message: '删除成功',
})
initEmployeeList();
}else{
ElMessage({
type: 'error',
message: res.data.description,
})
}
})
.catch(() => {
})
// initUserList();
}
const tempData=ref([])
const tempstore=()=>{
const temp=[]
tableData.value.map(item=>{
if(item.manStatus==0)
{
item.manStatus=true
}
else{
item.manStatus=false
}
if (item.auditStatus==1)
{
temp.push(item)
}
})
tableData.value=temp
// console.log(tableData.value)
tempData.value.slice(0,0)
tempData.value=tableData.value.slice(0,10)
//console.log(res.data.data)
}
const initEmployeeList=async()=>{
if (!query.value){
// let JS=window.sessionStorage.getItem("BUSINESS_STATE");
// const id=JSON.parse(JS).id
// console.log(id)
const res=await axios.post("manicurist/queryAll");
// console.log(res.data)
tableData.value=res.data.data
const t=[]
tableData.value.filter(item=>{
if(item.auditStatus==1&&item.businessId==getBusinessID()){
t.push(item)
}
})
tableData.value=t
const num=Number(tableData.value.length)
// console.log("initEmployeeList"+JSON.stringify(t))
total.value=num;
tempstore();
}else{
const res = await axios.get("manicurist/queryById", {manicuristId: query.value});
// console.log(res.data)
const temp = []
temp.push(res.data.data)
tableData.value = temp;
total.value = 1;
tempstore();
}
}
initEmployeeList();
const handleCurrentChange = (pageNum) => {
tempData.value=tableData.value.slice(pageNum*10-10,pageNum*10)
}
// =============================================
const colors = ref(['#99A9BF', '#F7BA2A', '#FF9900'])
</script>
<style lang="scss" scoped>
.header{
padding-bottom: 16px;
box-sizing: border-box;
}
.el-pagination{
padding-top: 15px;
box-sizing: border-box;
}
.demo-rate-block {
padding: 15px 0;
text-align: center;
border-right: solid 1px var(--el-border-color);
display: inline-block;
width: 49%;
box-sizing: border-box;
}
.demo-rate-block:last-child {
border-right: none;
}
.demo-rate-block .demonstration {
display: block;
color: var(--el-text-color-secondary);
font-size: 14px;
margin-bottom: 20px;
}
</style>

View File

@ -46,6 +46,14 @@
<div v-else></div>
</template>
</el-table-column>
<el-table-column label="商家" prop="businessId"/>
<el-table-column label="签约状态" prop="businessId">
<template #default="scope">
<div v-if="scope.row.businessId!==null||scope.row.businessId>0">已签约</div>
<div v-else style="color: red">未签约</div>
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" width="120px"/>
<el-table-column prop="email" label="邮箱" width="180px"/>
@ -252,6 +260,7 @@ const initEmployeeList=async()=>{
// console.log(res.data)
tableData.value=res.data.data;
let num=tableData.value.filter(item=>item.auditStatus==1)
total.value=num.length;
tempstore();
}else{

View File

@ -32,7 +32,7 @@ const initBreadcrumbList = () => {
}
watch(route, () => {
initBreadcrumbList();
console.log(route.matched)
// console.log(route.matched)
//console.log("breadcrumbList"+JSON.stringify(breadcrumbList))
}, {deep: true, immediate: true})
</script>

View File

@ -0,0 +1,68 @@
<template>
<el-tabs
v-model="editableTabsValue"
type="card"
class="demo-tabs"
closable
@tab-remove="removeTab"
@tab-change="changeTab"
>
<el-tab-pane
v-for="item in editableTabs"
:key="item.name"
:label="item.title"
:name="item.name"
>
</el-tab-pane>
</el-tabs>
</template>
<script setup>
import {getCurrentInstance, ref} from 'vue';
import router from "@/router";
//
const { proxy } = getCurrentInstance();
// 访
const editableTabs = proxy.$editableTabs;
const editableTabsValue = proxy.$editableTabsValue
const changeTab=(targetName)=>{
router.push('/'+targetName)
console.log(targetName)
}
const removeTab = (targetName) => {
// console.log(targetName)
const tabs = editableTabs.value
console.log(editableTabsValue.value)
let activeName = editableTabsValue.value
if (activeName === targetName) {
tabs.forEach((tab, index) => {
if (tab.name === targetName) {
const nextTab = tabs[index + 1] || tabs[index - 1]
if (nextTab) {
activeName = nextTab.name
}
}
})
}
editableTabsValue.value = activeName
editableTabs.value = tabs.filter((tab) => tab.name !== targetName)
if (editableTabs.value.length>1&&activeName!=editableTabsValue){
// console.log(editableTabs.value[0].name)
editableTabsValue.value = editableTabs.value[0].name
router.push('/'+editableTabs.value[0].name)
}
}
</script>
<style scoped>
</style>

View File

@ -36,14 +36,17 @@
<el-aside width="200px" class="sidebar-container"><Menu/></el-aside>
<el-container>
<el-header>
<div class="navbar">
<Breadcrumb/>
<div class="navbar-right">
<Avatar/>
</div>
</div>
</el-header>
<el-main>
<Tabs/>
<router-view/>
</el-main>
<el-footer><Footer/></el-footer>
@ -57,10 +60,10 @@ import Menu from '@/views/layout/menu'
import Breadcrumb from '@/views/layout/header/breadcrumb'
import Avatar from '@/views/layout/header/avatar'
import Footer from "@/views/layout/footer/index"
import modifyPassword from '@/views/modifyPassword/index'
import order from '@/views/order/index'
import smallType from '@/views/smallType/index.vue'
import bigType from '@/views/bigType/index.vue'
import Tabs from "@/views/layout/header/tabs.vue";
// main.js
</script>
<style lang="scss" scoped>
@ -69,6 +72,13 @@ import bigType from '@/views/bigType/index.vue'
width: 100%;
height: 100%;
}
.demo-tabs > .el-tabs__content {
padding: 32px;
color: #6b778c;
font-size: 32px;
font-weight: 600;
}
.navbar {
width: 100%;
height: 60px;

View File

@ -6,6 +6,8 @@
class="el-menu-vertical-demo"
default-active="home"
text-color="#fff"
@select="addTab"
router
>
@ -74,18 +76,18 @@
<el-icon><management /></el-icon>
<span>订单管理</span>
</template>
<el-menu-item index="orderReservation">
<el-menu-item index="userReservation">
<el-icon><tickets /></el-icon>
<span>上门预约</span>
</el-menu-item>
<el-menu-item index="order">
<el-menu-item index="orderReservation" >
<el-icon><tickets /></el-icon>
<span>到店服务</span>
</el-menu-item>
<!-- <el-menu-item index="order">-->
<!-- <el-icon><tickets /></el-icon>-->
<!-- <span>订单列表</span>-->
<!-- </el-menu-item>-->
<el-menu-item index="order">
<el-icon><tickets /></el-icon>
<span>订单列表</span>
</el-menu-item>
</el-sub-menu>
@ -129,6 +131,7 @@
</el-sub-menu>
</el-menu>
</div>
<!-- ===================================================================================-->
<div v-else>
<el-menu
active-text-color="#ffd04b"
@ -147,7 +150,7 @@
<el-icon><management /></el-icon>
<span>订单管理</span>
</template>
<el-menu-item index="orderReservation">
<el-menu-item index="userReservation">
<el-icon><tickets /></el-icon>
<span>上门预约</span>
</el-menu-item>
@ -179,11 +182,11 @@
<el-icon><tickets /></el-icon>
<span>美甲师管理</span>
</template>
<el-menu-item index="employee">
<el-menu-item index="nocontractemployee">
<el-icon><management /></el-icon>
<span>美甲师列表</span>
</el-menu-item>
<el-menu-item index="employeeVerify">
<el-menu-item index="contractemployee">
<el-icon><tickets /></el-icon>
<span>签约美甲师</span>
</el-menu-item>
@ -240,10 +243,37 @@ import
import { useStore } from 'vuex'
import axios from "@/util/axios";
import {ElMessage} from "element-plus";
import {ref} from "vue";
import {getCurrentInstance, ref} from "vue";
import {verifyPerson} from "@/util/time";
import {useRoute} from "vue-router";
import {getMenu} from '@/util/marked'
const store=useStore();
const ax=ref(true)
const { proxy } = getCurrentInstance();
// 访
const editableTabs = proxy.$editableTabs;
const editableTabsValue = proxy.$editableTabsValue
const route = useRoute();
const addTab = (key) => {
// console.log(route.matched[1].name)
// console.log(key)
editableTabs.value.push({
title: getMenu(key),
name: key
})
// console.log(editableTabsValue.value)
editableTabsValue.value = key
}
// =================================================================================
const initax=()=>{
ax.value=verifyPerson();
}

View File

@ -1,20 +1,22 @@
<template>
<el-card>
<el-row :gutter="20" class="header">
<el-col :span="7">
<el-input placeholder="请输入订单号..." clearable v-model="queryForm.orderNumber"></el-input>
</el-col>
<el-button type="button" :icon="Search" @click="initOrderList">搜索</el-button>
</el-row>
<el-table :data="tableData" stripe style="width: 100%" showOverflowTooltip>
<el-table-column prop="id" label="#ID" width="60" fixed/>
<el-table-column prop="orderNumber" label="订单号" width="220" fixed/>
<el-table-column prop="userName" label="用户昵称" width="200"/>
<el-table-column prop="totalPrice" label="订单总价" width="100"/>
<el-table-column prop="paymentStatus" label="订单状态" width="100"/>
<el-table-column prop="createTime" label="订单创建日期" width="200"/>
<el-table-column prop="updateTime" label="订单支付日期" width="200"/>
<el-table-column prop="userName" label="收货人" width="80"/>
<el-table-column prop="userId" label="用户ID" width="100" />
<el-table-column prop="username" label="用户昵称" width="200"/>
<el-table-column prop="businessId" label="商家ID" width="100"/>
<el-table-column prop="businessName" label="商家名称" width="150"/>
<el-table-column prop="manicuristId" label="美甲师ID" width="100"/>
<el-table-column prop="manicuristName" label="美甲师名称" width="150"/>
<el-table-column prop="orderId" label="订单ID" width="100"/>
<el-table-column prop="status" label="预约状态" width="100">
<template v-slot="scope" >
{{statusFormatter[scope.row.status]}}
</template>
</el-table-column>
<el-table-column prop="appointmentTime" label="预约时间" width="200"/>
<el-table-column prop="phone" label="联系电话" width="150"/>
<el-table-column prop="notes" label="描述" width="400"/>
<!-- <el-table-column label="操作" width="300" fixed="right">-->
@ -27,8 +29,7 @@
<!-- </el-table-column>-->
</el-table>
<el-pagination
v-model:currentPage="queryForm.current"
v-model:page-size="queryForm.pageSize"
v-model:currentPage="current"
:page-sizes="[10, 20, 30, 40,50]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@ -40,144 +41,118 @@
<Dialog v-model:="dialogVisible" :id="id"></Dialog>
</template>
<script setup>
import {Search,Delete} from '@element-plus/icons-vue'
import { ref} from 'vue'
import axios from "@/util/axios";
import Dialog from "@/views/order/dialog/index.vue";
import { ElMessage, ElMessageBox } from 'element-plus'
import {useRoute} from "vue-router";
const current=ref();
let params=useRoute().query
const claimStatusRef=ref([]);
// const handleDelete=(id)=>{
// ElMessageBox.confirm(
// '',
// '',
// {
// confirmButtonText: '',
// cancelButtonText: '',
// type: 'warning',
// }
// )
// .then(async () => {
// let res=await axios.get("admin/delete/"+id)
// if (res.data.code==0){
// ElMessage({
// type: 'success',
// message: '',
// })
// initReservation();
// }else{
// ElMessage({
// type: 'error',
// message: res.data.msg,
// })
// }
//
// })
// .catch(() => {
//
// })
// }
const handleDelete=(id)=>{
ElMessageBox.confirm(
'您确认要删除这个订单记录吗吗?',
'系统提示',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(async () => {
let res=await axios.get("admin/delete/"+id)
if (res.data.code==0){
ElMessage({
type: 'success',
message: '删除成功',
})
initOrderList();
}else{
ElMessage({
type: 'error',
message: res.data.msg,
})
}
})
.catch(() => {
})
}
const handleOrderStatus=(id,status)=>{
ElMessageBox.confirm(
'您确认要更新这个订单状态吗?',
'系统提示',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(async () => {
let res=await axios.post("admin/updateStatus",{id:id,status:status})
if (res.data.code==0){
ElMessage({
type: 'success',
message: '执行成功',
})
initOrderList();
}else{
ElMessage({
type: 'error',
message: res.data.msg,
})
}
})
.catch(() => {
})
}
// const handleOrderStatus=(id,status)=>{
// ElMessageBox.confirm(
// '',
// '',
// {
// confirmButtonText: '',
// cancelButtonText: '',
// type: 'warning',
// }
// )
// .then(async () => {
// let res=await axios.post("admin/updateStatus",{id:id,status:status})
// if (res.data.code==0){
// ElMessage({
// type: 'success',
// message: '',
// })
// initReservation();
// }else{
// ElMessage({
// type: 'error',
// message: res.data.msg,
// })
// }
//
// })
// .catch(() => {
//
// })
// }
const dialogVisible=ref(false)
const handleDialogValue=(orderId)=>{
id.value=orderId;
dialogVisible.value=true;
}
const id=ref(-1);
const statusFormatter=['已确认 ','已完成','已取消']
const queryForm=ref({
orderNumber:'',
current:1,
pageSize:10
})
const total=ref(0)
const tableData =ref([])
const initOrderList=async()=>{
const res=await axios.post("orders/list/page",queryForm.value);
//console.log(res.data.data)
// const temp=[];
// temp.push(res.data.data)
// console.log(res.data.data)
claimStatusRef.value.splice(0,claimStatusRef.value.length);
const initReservation=async()=>{
const res=await axios.post("appointments/query",{id: JSON.parse(params.product)});
console.log(JSON.parse(params.product))
if(res.data.data){
tableData.value=res.data.data.records;
tableData.value.forEach(item => {
if (item.claimStatus==0) {
claimStatusRef.value.push(item)
}
})
tableData.value=claimStatusRef.value
total.value=Number(claimStatusRef.value.length);
res.data.data.forEach(item=>{
if(!item.serviceMode){
tableData.value.push(item)
}
})
total.value=Number(tableData.value.length);
}
else{
ElMessage.error(res.data.description);
}
}
initOrderList();
initReservation();
const handleSizeChange = (pageSize) => {
queryForm.value.current=1;
queryForm.value.pageSize=pageSize;
initOrderList();
//queryForm.value.current=1;
//queryForm.value.pageSize=pageSize;
initReservation();
}
const handleCurrentChange = (current) => {
queryForm.value.current=current;
initOrderList();
//queryForm.value.current=current;
initReservation();
}
const statusFormatter=(row)=>{
switch (row.status){
case 1:
return "待支付";
case 2:
return "待发货";
case 3:
return "退款/退货";
}
}
</script>
<style lang="scss" scoped>
.header{

View File

@ -0,0 +1,160 @@
<template>
<el-card>
<el-row :gutter="20" class="header">
<el-col :span="7">
<el-input placeholder="请输入用户昵称..." clearable v-model="queryForm.username"></el-input>
</el-col>
<el-col :span="4">
<el-select
v-model="queryForm.userRole"
size="default"
placeholder="用户角色"
style="width: 100%"
>
<el-option
v-for="(item,index) in options"
:key="item.indexOf()"
:label="item"
:value="index"
/>
</el-select>
</el-col>
<el-button type="button" :icon="Search" @click="initUserList" >搜索</el-button>
</el-row>
<el-table :data="tableData" stripe style="width: 100%;" showOverflowTooltip>
<el-table-column fixed prop="id" label="#ID" width="80" />
<el-table-column prop="username" label="用户昵称" width="150" />
<el-table-column prop="avatarUrl" label="头像" width="200">
<template v-slot="scope">
<el-popover
placement="right-start"
:width="200"
trigger="hover"
:content="scope.row.avatarUrl"
>
<template #reference>
<img :src="scope.row.avatarUrl" width="50" height="50"/>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="openId" label="openId" />
<el-table-column prop="phone" label="电话" width="120"/>
<el-table-column prop="email" label="email" width="200"/>
<el-table-column prop="userStatus" label="用户状态" width="200">
<template v-slot="scope">
<el-switch
disabled
v-model="scope.row.userStatus"
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
/>
</template>
</el-table-column>
<el-table-column prop="userRole" label="用户角色" width="200">
<template v-slot="scope">
<div v-if="scope.row.userRole===0">普通用户</div>
<div v-else-if="scope.row.userRole===1">管理员</div>
<div v-else-if="scope.row.userRole===2">商家</div>
<div v-else>美甲师</div>
</template>
</el-table-column>
<el-table-column prop="action" fixed="right" label="操作" min-width="100">
<template v-slot="scope" >
<el-button type="success" size="small" @click="handleValue(scope.row.id)">
上门预约
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:currentPage="queryForm.current"
v-model:page-size="queryForm.pageSize"
:page-sizes="[10, 20, 30, 40,50]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<!-- {{total}}-->
</el-card>
</template>
<script setup>
import {Search,Delete,Edit,DocumentAdd,Close,Check} from '@element-plus/icons-vue'
import {ref, watch} from 'vue'
import axios from "@/util/axios";
import { ElMessage,ElMessageBox } from "element-plus";
import {useRouter} from "vue-router"
const router=useRouter();
const queryForm=ref({
userRole:'',
username: '',
current:1,
pageSize:10
})
const options = [ '普通用户', '管理员', '商家', '美甲师']
const dialogTitle=ref('');
const handleValue=(ids)=>{
router.push({path:'/orderReservation',query:{id: JSON.stringify(ids)}})
}
const total=ref(0)
const tableData =ref([])
const initUserList=async()=>{
const res = await axios.post("user/list/page", queryForm.value);
if (res.data.data) {
tableData.value = res.data.data.records;
tableData.value.map(item=>{
if(item.userStatus==0)
{
item.userStatus=true
}
else{
item.userStatus=false
}
})
//console.log(res.data.data)
total.value = Number(res.data.data.total);
}
else{
ElMessage.error(res.data.description);
}
}
initUserList();
const handleSizeChange = (pageSize) => {
queryForm.value.current=1;
queryForm.value.pageSize=pageSize;
initUserList();
}
const handleCurrentChange = (current1) => {
queryForm.value.current=current1;
initUserList();
}
</script>
<style lang="scss" scoped>
.header{
padding-bottom: 16px;
box-sizing: border-box;
}
.el-pagination{
padding-top: 15px;
box-sizing: border-box;
}
</style>

View File

@ -25,54 +25,12 @@
<script setup>
import { ref } from 'vue'
let tabIndex = 2
const editableTabsValue = ref('2')
const editableTabs = ref([
{
title: 'Tab 1',
name: '1',
content: 'Tab 1 content',
},
{
title: 'Tab 2',
name: '2',
content: 'Tab 2 content',
},
])
const addTab = (targetName) => {
const newTabName = `${++tabIndex}`
editableTabs.value.push({
title: 'New Tab',
name: newTabName,
content: 'New Tab content',
})
editableTabsValue.value = newTabName
}
const removeTab = (targetName) => {
const tabs = editableTabs.value
let activeName = editableTabsValue.value
if (activeName === targetName) {
tabs.forEach((tab, index) => {
if (tab.name === targetName) {
const nextTab = tabs[index + 1] || tabs[index - 1]
if (nextTab) {
activeName = nextTab.name
}
}
})
}
editableTabsValue.value = activeName
editableTabs.value = tabs.filter((tab) => tab.name !== targetName)
}
</script>
<style>
.demo-tabs > .el-tabs__content {
padding: 32px;
color: #6b778c;
font-size: 32px;
font-weight: 600;
}
</style>

View File

@ -50,12 +50,12 @@
@change="updateSwtich(scope.row)"
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
/>
<!-- <div v-if="scope.row.userStatus===0" style="color: red">-->
<!-- 禁用-->
<!-- </div>-->
<!-- <div style="color: lawngreen" v-else>-->
<!-- 启用-->
<!-- </div>-->
<!-- <div v-if="scope.row.userStatus===0" style="color: red">-->
<!-- 禁用-->
<!-- </div>-->
<!-- <div style="color: lawngreen" v-else>-->
<!-- 启用-->
<!-- </div>-->
</template>
</el-table-column>
<el-table-column prop="userRole" label="用户角色" width="200">
@ -67,9 +67,9 @@
</template>
</el-table-column>
<el-table-column prop="createTime" label="注册日期" width="200">
<!-- <template v-slot="scope">-->
<!-- {{ parseTime(scope.row.createTime, "{y}-{m}-{d}") }}-->
<!-- </template>-->
<!-- <template v-slot="scope">-->
<!-- {{ parseTime(scope.row.createTime, "{y}-{m}-{d}") }}-->
<!-- </template>-->
</el-table-column>
<el-table-column prop="updateTime" label="最后登录日期" width="200"/>
<el-table-column prop="action" fixed="right" label="操作" min-width="220">
@ -92,16 +92,16 @@
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<!-- {{total}}-->
<!-- {{total}}-->
</el-card>
<Dialog v-model="UdialogVisible" :id="id" :dialogTitle="dialogTitle"
@initUserList="initUserList"></Dialog>
<AddDialog v-model="UdialogaddVisible" :dialogTitle="dialogTitle"
@initUserList="initUserList"></AddDialog>
@initUserList="initUserList"></AddDialog>
<UpdateDialog v-model="UdialogUpdateVisible" :id="id" :dialogTitle="dialogTitle"
@initUserList="initUserList"></UpdateDialog>
@initUserList="initUserList"></UpdateDialog>
</template>
<script setup>
@ -167,13 +167,13 @@ const handleDialogValue=(ids)=>{
UdialogVisible.value=true
}
const handleUpdateDialogValue=(ids)=>{
const handleUpdateDialogValue=(ids)=>{
id.value=ids;
id.value=ids;
dialogTitle.value="用户修改"
UdialogUpdateVisible.value=true
}
dialogTitle.value="用户修改"
UdialogUpdateVisible.value=true
}
const handleAddDialogValue=()=>{
dialogTitle.value="用户添加"
@ -186,7 +186,7 @@ const handleAddDialogValue=()=>{
//
const handleDelete=(id)=>{
// console.log(id)
// console.log(id)
ElMessageBox.confirm(
'您确定要删除这条记录吗?',
'系统提示',
@ -222,23 +222,23 @@ const total=ref(0)
const tableData =ref([])
const initUserList=async()=>{
// // console.log(query)
// if (!query.value) {
// const res = await axios.post("user/list/page", queryForm.value);
// // console.log(res)
// tableData.value = res.data.data.records;
// //console.log(res.data.data)
// total.value = Number(res.data.data.total);
// }
// else{
// const res=await axios.get("user/getById", {id:query.value});
// // console.log(res.data.data)
// const temp=[];
// temp.push(res.data.data)
// tableData.value=temp;
// total.value=1;
// }
// console.log(queryForm.value)
// // console.log(query)
// if (!query.value) {
// const res = await axios.post("user/list/page", queryForm.value);
// // console.log(res)
// tableData.value = res.data.data.records;
// //console.log(res.data.data)
// total.value = Number(res.data.data.total);
// }
// else{
// const res=await axios.get("user/getById", {id:query.value});
// // console.log(res.data.data)
// const temp=[];
// temp.push(res.data.data)
// tableData.value=temp;
// total.value=1;
// }
// console.log(queryForm.value)
const res = await axios.post("user/list/page", queryForm.value);
if (res.data.data) {