Compare commits

1 Commits
Author SHA1 Message Date
hezhidong 14d0f1a948 初始化 2024-10-10 12:08:37 +08:00
108 changed files with 33704 additions and 17756 deletions
-8
View File
@@ -1,8 +0,0 @@
{
"hash": "b40a7241",
"configHash": "e4e9a696",
"lockfileHash": "e3b0c442",
"browserHash": "3514e43b",
"optimized": {},
"chunks": {}
}
-3
View File
@@ -1,3 +0,0 @@
{
"type": "module"
}
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
+1084 -7250
View File
File diff suppressed because it is too large Load Diff
+2 -10
View File
@@ -4,13 +4,12 @@
"private": true,
"scripts": {
"build": "vite build",
"dev": "vite",
"dev": "vite --host",
"preview": "vite preview"
},
"dependencies": {
"@braks/vue-flow": "^0.4.38",
"@element-plus/icons-vue": "^1.1.4",
"@hellowuxin/mindmap": "^2.1.4",
"@kangc/v-md-editor": "^2.3.15",
"@wangeditor/editor": "^5.1.14",
"@wangeditor/editor-for-vue": "^5.1.12",
@@ -19,20 +18,13 @@
"echarts": "^5.3.3",
"element-plus": "^2.1.11",
"js-base64": "^3.7.2",
"jsmind": "^0.6.4",
"markmap-common": "^0.15.0",
"markmap-lib": "^0.15.2",
"markmap-toolbar": "^0.15.0",
"markmap-view": "^0.15.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"screenfull": "^6.0.1",
"sortablejs": "^1.15.0",
"video.js": "^7.20.3",
"vue": "^3.2.25",
"vue-router": "^4.0.13",
"vue-video-player": "^6.0.0",
"vue3-mindmap": "^0.5.12",
"vue3-print-nb": "^0.1.4",
"vuedraggable": "^4.1.0",
"vuex": "^4.0.2",
@@ -41,7 +33,7 @@
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.3.1",
"sass": "^1.79.5",
"sass": "^1.51.0",
"vite": "^2.9.7",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "^2.9.6",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

-9
View File
@@ -1,9 +0,0 @@
import service from "../request.js";
export function updateAdmin(params) {
return service({
method: "put",
url: '/sys/user/password',
data: params,
});
}
-30
View File
@@ -1,30 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/application';
// 待审核列表
export function getApplicationList(query) {
return service({
method: "get",
url: `${API_BASE_URL}/list`,
data: query,
});
}
// 通过
export function approveApplication(query) {
return service({
method: "get",
url: `${API_BASE_URL}/approve`,
data: query,
});
}
// 拒绝
export function rejectApplication(query) {
return service({
method: "get",
url: `${API_BASE_URL}/reject`,
data: query,
});
}
-38
View File
@@ -1,38 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/goods';
// 服务项目列表
export function getGoodsList(query) {
return service({
method: "get",
url: `${API_BASE_URL}/list`,
data: query,
});
}
// 添加服务项目
export function addGoods(query) {
return service({
method: "post",
url: `${API_BASE_URL}`,
data: query,
});
}
// 更新服务项目
export function updateGoods(query) {
return service({
method: "put",
url: `${API_BASE_URL}`,
data: query,
});
}
// 删除服务项目
export function delGoods(query) {
return service({
method: "delete",
url: `${API_BASE_URL}/${query}`,
data: query,
});
}
+2 -2
View File
@@ -5,7 +5,7 @@ import service from "../request.js";
export function LoginInfo(query) {
return service({
method: "POST",
url: "/login",
url: "/permission/LoginInfo",
data: query,
});
}
@@ -72,4 +72,4 @@ export function cardlists(query) {
url: "/permission/cardlists",
data: query,
});
}
}
-19
View File
@@ -1,19 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/order';
// 订单列表
export function getOrderList(query) {
return service({
method: "get",
url: `${API_BASE_URL}/all/list`,
params: query,
});
}
// 导出订单
export function exportOrder(query) {
const urlParams = new URLSearchParams(query);
return `https://api.cqcxj.cn/order/list/export?${urlParams.toString()}`;
}
-28
View File
@@ -1,28 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/application';
// 工作岗位资格申请审批管理
export function getApplyList(query) {
return service({
method: "get",
url: `${API_BASE_URL}/list`,
params: query,
});
}
// 工作岗位资格申请拒绝
export function reject(applicationId) {
return service({
method: "put",
url: `${API_BASE_URL}/reject/`+applicationId
});
}
// 工作岗位资格申请通过
export function approve(applicationId) {
return service({
method: "put",
url: `${API_BASE_URL}/approve/`+applicationId
});
}
-38
View File
@@ -1,38 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/schedule';
// 获取排班人员吗
export function getScheduleList(params) {
return service({
method: "get",
url: `${API_BASE_URL}/${params.timeQuantumId}?&date=${params.date}&roleId=${params.roleId}`,
data: params
});
}
// 添加排班
export function addSchedule(params) {
return service({
method: "post",
url: `${API_BASE_URL}`,
data: params,
});
}
// 修改排班
export function updateSchedule(params) {
return service({
method: "put",
url: `${API_BASE_URL}`,
data: params,
});
}
// 删除排班
export function delSchedule(params) {
return service({
method: "delete",
url: `${API_BASE_URL}/${params.id}`,
data: params,
});
}
-36
View File
@@ -1,36 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/time/quantum';
// 获取排班时段列表
export function listQuantum() {
return service({
method: "get",
url: `${API_BASE_URL}`
});
}
// 修改排班时段
export function addQuantum(params) {
return service({
method: "post",
url: `${API_BASE_URL}`,
data: params,
});
}
// 修改排班时段
export function updateQuantum(params) {
return service({
method: "put",
url: `${API_BASE_URL}`,
data: params,
});
}
// 删除排班时段
export function delQuantum(params) {
return service({
method: "delete",
url: `${API_BASE_URL}/${params.id}`
});
}
-20
View File
@@ -1,20 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/user';
// 查询勘测人员列表
export function listSurveyorsUser(query) {
return service({
method: "get",
url: `${API_BASE_URL}/surveyors`,
params: query
});
}
// 查询勘测人员列表
export function listMaintenanceUser(query) {
return service({
method: "get",
url: `${API_BASE_URL}/maintenance`,
params: query
});
}
-29
View File
@@ -1,29 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/config';
// 修改配置
export function updateSystem(params) {
return service({
method: "put",
url: `${API_BASE_URL}`,
data: params,
});
}
// 获取配置信息列表(全部配置)
export function getConfigList(query) {
return service({
method: "get",
url: `${API_BASE_URL}/list`,
data: query,
});
}
// 更新单个配置项内容(仅更新内容字段)
export function updateConfig(query) {
return service({
method: "put",
url: `${API_BASE_URL}`,
data: query,
});
}
-11
View File
@@ -1,11 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/file';
// 上传文件
export function addFile(formData) {
return service({
method: "post",
url: `${API_BASE_URL}`,
data: formData
});
}
-38
View File
@@ -1,38 +0,0 @@
import service from "../request.js";
const API_BASE_URL = '/user';
// 客户列表
export function getUserList(roleld, query) {
return service({
method: "get",
url: `${API_BASE_URL}/${roleld}`,
params: query,
});
}
// 获取勘测人员列表
export function getSurveyorsList(query) {
return service({
method: "get",
url: `${API_BASE_URL}/surveyors`,
data: query,
});
}
// 获取维修人员列表
export function getMaintenanceList(query) {
return service({
method: "get",
url: `${API_BASE_URL}/maintenance`,
data: query,
});
}
// 删除人员
export function deleteUser(ItemId) {
return service({
method: "delete",
url: `/application/role/${ItemId}`,
});
}
+28 -93
View File
@@ -1,109 +1,44 @@
import axios from "axios";
import { ElMessage, ElMessageBox } from "element-plus";
import router from "../router/router";
import {
ElMessage
} from "element-plus";
const errorCode = {
401: "登录状态已过期,即将返回首页重新登录。",
403: "当前操作没有权限",
404: "访问资源不存在",
default: "系统未知错误,请反馈给管理员",
};
const url = "https://api.cqcxj.cn";
const service = axios.create({
baseURL: url,
timeout: 60000,
timeout: 5000,
});
// Request interceptors
service.interceptors.request.use(
(config) => {
if (localStorage.getItem("token")) {
config.headers["Authorization"] =
"Bearer " + localStorage.getItem("token");
}
(config) => {
if (localStorage.getItem('token'))
config.headers.token = localStorage.getItem('token')
if (config.url === "/login") {
config.headers["Content-Type"] = "multipart/form-data";
} else {
config.headers["Content-Type"] = "application/json";
}
if (config.url === "/file") {
config.headers["Content-Type"] = "multipart/form-data";
}
let params = config.params;
let newData = {};
for (let key in params) {
if (params[key] !== null && params[key] !== "") {
newData[key] = params[key];
}
}
config.params = newData;
return config;
},
(error) => {
Promise.reject(error).then(() => {});
}
return config;
},
(error) => {
Promise.reject(error);
}
);
// Response interceptors
service.interceptors.response.use(
(res) => {
// 对响应数据做点什么
const response = res.data;
const code = res.data.code || 200;
const message = errorCode[code] || res.data.msg || errorCode["default"];
if (code === 401) {
if (res.code === 401 || res.code === 4001) {
// 清除浏览器全部临时缓存
sessionStorage.clear();
localStorage.clear();
router.push("/login");
// store.commit('setMenuData', {});
// resetRouter(); // 重置路由
ElMessageBox.alert("你已被登出,请重新登录", "提示", {})
.then(() => {})
.catch(() => {});
}
} else if (code === 500) {
// Message({ message: msg, type: 'error' })
ElMessage.error(message);
return Promise.reject(new Error(msg));
} else if (code === 601) {
// Message({ message: msg, type: 'warning' })
ElMessage.error(message);
return Promise.reject("error");
} else if (code !== 200) {
ElMessage.error(message);
return Promise.reject("error");
} else {
return response;
}
},
(error) => {
console.log(error.response.data); // 获取错误状态码
// 对响应错误做点什么
if (error.message.indexOf("timeout") !== -1) {
ElMessage.error("网络超时");
} else if (error.message === "Network Error") {
ElMessage.error("网络连接错误");
} else if (error.response.data.code === "401") {
sessionStorage.clear();
localStorage.clear();
router.push("/login");
ElMessage.error(error.response.data.msg);
} else {
ElMessage.error(
error.response.data.msg ||
error.response.data.error ||
error.response.data.errMessage
);
}
return Promise.reject(error);
(response) => {
if (response.status !== 200) {
ElMessage({
type: "error",
message: "服务器忙,请稍后再试~",
});
return;
}
return response;
},
(error) => {
// do something
return Promise.reject(error);
}
);
export default service;
export default service;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

+24 -37
View File
@@ -1,23 +1,21 @@
<template>
<el-tag
ref="tagRef"
v-for="tag in tags"
:key="tag.title"
class="mR10 tabs"
:closable="tag.close"
:effect="tag.checked ? 'dark' : 'plain'"
@click="tagChange(tag)"
@close="delectTag(tag, index)"
>
<template class="spanmenu">
<div class="tags">
<el-tag
ref="tagRef"
v-for="tag in tags"
:key="tag.title"
class="mR10 tabs"
:closable="tag.close"
:effect="tag.checked ? 'dark' : 'plain'"
@click="tagChange(tag)"
@close="delectTag(tag, index)"
>
<el-icon class="tabs-icon">
<component :is="tag.icon"></component>
</el-icon>
{{ tag.title }}
</template>
</el-tag>
</el-tag>
</div>
</template>
<script setup>
@@ -25,14 +23,12 @@ import { useRoute, useRouter } from 'vue-router'
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import store from '../../store/index.js'
import { useStore } from 'vuex'
const tabsMenuValue = ref('')
const nameScroll = ref(false)
const tagRef = ref()
const route = useRoute()
const router = useRouter()
const globalStore = useStore() // 该方法用于返回store 实例
// 监听路由的变化(防止浏览器后退/前进不变化 tabsMenuValue)
watch(
() => route.path,
@@ -50,43 +46,34 @@ watch(
immediate: true,
}
)
const tags = store.getters.tabsMenuList
const tagChange = (item) => {
item.checked = true
router.push(item.url)
}
const delectTag = (item, index) => {
globalStore.dispatch('tabs/delectTag', item)
}
onMounted(() => {
nextTick(() => {})
})
</script>
<style lang="scss" scoped>
.mR10 {
margin-right: 10px;
}
.tabs {
.tags {
width: 95%;
overflow: hidden;
height: 100%;
display: flex;
align-items: center;
height: 30px;
padding: 0 10px; /* 调整内边距 */
border-radius: 4px; /* 圆角 */
cursor: pointer;
.tabs-icon {
margin-right: 5px; /* 图标和文字之间的间距 */
flex-flow: row;
overflow: scroll;
white-space: nowrap;
&::-webkit-scrollbar {
display: none;
}
.spanmenu{
display: flex;
align-items: center;
.tabs {
height: 30px;
}
}
</style>
+1 -1
View File
@@ -4,7 +4,7 @@
<div class="avatar">
<img src="../../../assets/images/avart.jpg" alt="avatar" />
</div>
<span class="username" :style="{ color: themeConfig.footColor }">管理员</span>
<span class="username" :style="{ color: themeConfig.footColor }">BIG CUTE</span>
</div>
<template #dropdown>
<el-dropdown-menu>
+1 -1
View File
@@ -14,7 +14,7 @@
<!-- <Driver></Driver> -->
<fullScreen></fullScreen>
<avatar></avatar>
<!-- <setting></setting>-->
<setting></setting>
</div>
</div>
</template>
+2
View File
@@ -15,11 +15,13 @@
}
.main-tabs {
width: 100%;
margin-bottom: 10px;
background-color: #fff;
border: 0;
box-shadow: none;
overflow: hidden;
height: 30px;
}
.el-main {
+1 -1
View File
@@ -8,7 +8,7 @@
<Header></Header>
</el-header>
<el-main>
<div class="main-tabs flx-row p10" v-if="themeConfig.istags">
<div class="main-tabs flx-row" v-if="themeConfig.istags">
<tabs></tabs>
</div>
+7 -3
View File
@@ -9,7 +9,7 @@
}"
>
<div class="logo" v-if="!store.getters.isCollapse">
<img src="../../assets/logo.png" alt="" style="margin-right: 5px" /> 创兴佳
<img src="../../assets/logo.png" alt="" style="margin-right: 5px" /> BIG CUTE
</div>
<div class="logo" v-else>
<img src="../../assets/logo.png" alt="" />
@@ -33,7 +33,7 @@
<script setup>
import { computed, onMounted, reactive, ref } from "vue";
import { menuListItem } from "../../mock/permission";
import { getMenuList } from "../../api/modules/index.js";
import store from "../../store/index.js";
import menuItems from "./components/menuItems.vue";
// 引入本地路由表渲染导航栏
@@ -54,8 +54,12 @@ const themeConfig = store.getters.themeConfig;
// 菜单表存在后端的操作方式
onMounted(() => {
getMenuList().then((res) => {
menuList.value = res.data.data.menuList;
console.log(menuItems.value);
});
// 获取本地菜单表渲染
menuList.value = menuListItem;
// menuList.value = menuTable;
});
</script>
+1 -11
View File
@@ -5,16 +5,6 @@ const menuTable = [
url: "/home",
icon: "HomeFilled",
},
{
title: "用户管理",
url: "/home",
icon: "HomeFilled",
},
{
title: "服务项目",
url: "/goods",
icon: "HomeFilled",
},
{
title: "页面管理",
url: "/page",
@@ -43,7 +33,7 @@ const menuTable = [
],
},
{
url: "/system",
title: "/system",
title: "表格管理",
icon: "Grid",
children: [
+3
View File
@@ -10,12 +10,15 @@ import zhCn from "element-plus/es/locale/lang/zh-cn";
import directives from "./instruction/index.js";
import "element-plus/dist/index.css";
import App from "./App.vue";
import "./mock/index.js";
import * as ELIcons from "@element-plus/icons-vue";
import VMdEditor from "@kangc/v-md-editor";
import vuepressTheme from "@kangc/v-md-editor/lib/theme/vuepress.js";
import "@kangc/v-md-editor/lib/style/base-editor.css";
import "@kangc/v-md-editor/lib/theme/style/vuepress.css";
VMdEditor.use(vuepressTheme);
const app = createApp(App);
// 小图标引用
+25
View File
@@ -0,0 +1,25 @@
import Mock from "mockjs";
import {
UserList,
addUserList,
listUpdate,
LoginInfo,
getMenuList,
Newslist,
orderLists,
homeList,
noticeLists,
cardlists
} from "./permission.js";
Mock.mock("/permission/LoginInfo", "post", LoginInfo);
Mock.mock("/permission/getMenuList", "get", getMenuList);
Mock.mock("/permission/UserList", "get", UserList);
Mock.mock("/permission/addUserList", "post", addUserList);
Mock.mock("/permission/listUpdate", "post", listUpdate);
Mock.mock("/permission/Newslist", "get", Newslist);
Mock.mock("/permission/orderLists", "get", orderLists);
Mock.mock("/permission/homeList", "get", homeList);
Mock.mock("/permission/noticeLists", "get", noticeLists);
Mock.mock("/permission/cardlists", "get", cardlists);
+476 -97
View File
@@ -1,115 +1,494 @@
// 引入mockjs
import Mock from "mockjs";
import {
options
} from "../views/home/options";
const Random = Mock.Random;
export const menuListItem = [
{
let menuList = [{
title: "首页",
url: "/home",
icon: "HomeFilled",
},
{
title: "系统配置",
url: "/system",
icon: "Setting",
children: [
{
title: "小程序首页",
url: "/homesite",
icon: "Menu",
title: "页面管理",
url: "/page",
icon: "Checked",
children: [{
title: "表单页",
url: "/form",
icon: "Checked",
children: [{
title: "基础表单",
url: "/baseForm",
icon: "Menu",
},
{
url: "/stepFrom",
title: "步骤表单",
icon: "Menu",
},
{
url: "/advancedForm",
title: "高级表单",
icon: "Menu",
},
],
},
{
title: "客服电话",
url: "/customer",
icon: "Menu",
title: "/system",
title: "表格管理",
icon: "Grid",
children: [{
url: "/Department",
title: "基础表格",
icon: "Menu",
},
{
url: "/UserList",
title: "内嵌表格",
icon: "Menu",
},
{
url: "/RoleList",
title: "滑动加载",
icon: "Menu",
},
{
url: "/MenuList",
title: "可编辑Table",
icon: "Menu",
},
{
url: "/importExcel",
title: "导入Excel",
icon: "Menu",
},
],
},
{
title: "活动管理",
url: "/activity",
icon: "Menu",
},
{
title: "重复下单开关",
url: "/switchOrder",
icon: "Menu",
url: "/goods",
title: "列表页",
icon: "List",
children: [{
url: "/goodCategory",
title: "基础列表",
icon: "Menu",
},
{
url: "/cardList",
title: "卡片列表",
icon: "Menu",
},
{
url: "/searchList",
title: "搜索列表",
icon: "Menu",
},
],
}, {
url: "/ErrorMessage",
title: "异常页面",
icon: "WarningFilled",
children: [{
url: "/404",
title: "404",
icon: "Menu",
},
{
url: "/500",
title: "500",
icon: "Menu",
},
],
},
]
},
{
title: "服务项目",
url: "/goods",
icon: "Goods",
},
{
title: "订单管理",
url: "/order",
icon: "ShoppingCart",
},
{
title: "用户管理",
url: "/user",
icon: "User",
children: [
{
title: "客户",
url: "/index",
icon: "Menu",
},
{
title: "勘测人员",
url: "/reconnaissanceList",
icon: "Menu",
},
{
title: "维修人员",
url: "/maintainList",
icon: "Menu",
},
]
},
{
title: "工程师审核",
url: "/engineer",
icon: "Postcard",
children: [
{
title: "勘测工程师",
url: "/reconnaissance",
icon: "Menu",
},
{
title: "维修工程师",
url: "/maintain",
icon: "Menu",
}
]
},
{
title: "工程师排班",
url: "/scheduling",
icon: "Calendar",
children: [
{
title: "排班时段",
url: "/timeFrame",
icon: "Menu",
},
{
title: "勘测工程师",
url: "/reconnaissanceScheduling",
icon: "Menu",
},
{
title: "维修工程师",
url: "/maintainScheduling",
icon: "Menu",
}
]
},
{
title: "修改资料",
url: "/edit",
icon: "Edit",
},
{
title: "图形图表",
url: "/echarts",
icon: "Histogram",
children: [{
title: "地图",
url: "/echarts/map",
icon: "Menu",
children: [{
url: "/baidumap",
title: "百度地图",
icon: "Menu",
},
// {
// url: "/gaodemap",
// title: "高德地图",
// icon: "Menu",
// },
],
},
{
title: "雷达图",
url: "/radar",
icon: "Menu",
},
{
title: "柱状图",
url: "/histogram",
icon: "Menu",
},
{
title: "折线图",
url: "/line",
icon: "Menu",
},
],
},
{
url: "/able",
title: "功能",
icon: "HelpFilled",
children: [{
url: "/watermark",
title: "水印",
icon: "Menu",
},
{
url: "/countTo",
title: "数字动画",
icon: "Menu",
},
{
url: "/batchImport",
title: "图片上传",
icon: "Menu",
},
{
url: "/fileImport",
title: "文件上传",
icon: "Menu",
},
{
url: "markdown",
icon: "Platform",
title: "编辑器",
children: [{
url: "/wangEditor",
title: "富文本编辑器",
icon: "Menu",
},
{
url: "/markdown",
title: "markdown",
icon: "Menu",
},
],
},
{
url: "/strength",
title: "密码强度",
icon: "Menu",
},
{
url: "/validation",
title: "验证组件",
icon: "Menu",
},
{
url: "/guide",
title: "引导页",
icon: "Menu",
},
{
url: "/embedded",
title: "内嵌页",
icon: "Menu",
},
],
},
{
url: "/directives",
title: "自定义指令",
icon: "Stamp",
children: [{
url: "/copy",
title: "复制",
icon: "Menu",
},
{
url: "/Drag",
title: "拖拽",
icon: "Menu",
},
{
url: "/debounceDirect",
title: "防抖指令",
icon: "Menu",
},
{
url: "/throttle",
title: "节流指令",
icon: "Menu",
},
{
url: "/longPress",
title: "长按指令",
icon: "Menu",
},
],
},
{
url: "/flow",
title: "图形编辑器",
icon: "BrushFilled",
//
children: [{
url: "/flowCat",
title: "流程图",
icon: "Menu",
}, ],
},
{
url: "/video",
title: "视频播放器",
icon: "VideoCameraFilled",
//
children: [{
url: "/video",
title: "视频播放器",
icon: "Menu",
}, ],
},
{
url: "/DataReport",
title: "数据统计",
icon: "TrendCharts",
children: [{
url: "/demo1",
title: "项目一",
icon: "Menu",
}, ],
},
// {
// url: "/material",
// title: "素材中心",
// icon: "PictureFilled",
// children: [{
// url: "/materialIndex",
// title: "素材管理",
// icon: "Menu",
// }, ],
// },
{
url: "/user",
title: "个人中心",
icon: "Avatar",
children: [{
url: "/user",
title: "关于我",
icon: "Menu",
}, ],
},
];
export const LoginInfo = (options) => {
console.log(options, "接收post参数");
const {
username,
password
} = JSON.parse(options.body);
if (username == "admin" && password != "123456") {
return {
code: "-200",
data: {
message: "用户不存在",
},
};
} else {
return {
code: "200",
data: {
user_id: Random.id(),
name: Random.cname(),
token: Random.guid(),
image: "https://img2.baidu.com/it/u=2859542338,3761174075&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1660064400&t=6fe6057370cbe369654ff2e132d02a37",
},
};
}
};
export const getMenuList = (options) => {
const obj = JSON.parse(options.body);
return {
code: 200,
data: {
menuList: menuList,
},
};
};
// 用户列表
let userList = [];
for (let index = 0; index < 50; index++) {
let obj = {
id: Random.id(),
username: Random.cname(),
email: Random.email(),
date: Random.date(),
address: Random.city(true),
content: Random.csentence(),
};
userList.push(obj);
}
const param2Obj = (url) => {
let obj = JSON.parse(url);
let page = obj.page;
console.log(page);
return page;
};
export const UserList = (options) => {
const currentPage = param2Obj(options.body);
let cameraData = userList.filter((item, index) => {
return index >= (currentPage - 1) * 10 && index < currentPage * 10;
});
return {
code: 200,
data: {
total: userList.length,
userList: cameraData,
},
};
};
export const addUserList = (options) => {
console.log("传过来的数据" + JSON.parse(options.body));
let obj = JSON.parse(options.body);
obj.id = Random.id();
userList.unshift(obj); // 将前台返回来的数据,拼接到数组中。
return {
data: userList,
id: obj.id,
};
};
// 数据的修改操作
export const listUpdate = (options) => {
let obj = JSON.parse(options.body);
userList = userList.map((val) => {
return val.id == obj.id ? obj : val;
});
return {
data: userList,
};
};
export const Newslist = (options) => {
let obj = JSON.parse(options.body);
let newList = [];
for (let i = 0; i < 10; i++) {
let item = {
title: Random.csentence(5, 8), // Random.csentence( min, max )
notifyPic: Random.dataImage("300x250", "mock的图片"), // Random.dataImage( size, text ) 生成一段随机的 Base64 图片编码
notifyType: Random.integer(1, 3), //随机生成1-3的Integer
isTop: Random.integer(1, 2), //随机生成1-2的Integer
createUser: Random.cname(), // Random.cname() 随机生成一个常见的中文姓名
email: Random.email(),
number: '$' + Random.integer(100, 5000) + '.00',
createTime: Random.date() + " " + Random.time(),
pay_state: '100' + Random.integer(1, 3),
};
newList.push(item);
}
return {
data: newList,
};
};
export const orderLists = (options) => {
let obj = JSON.parse(options.body);
let orderList = [];
for (let i = 0; i < 60; i++) {
let item = {
goodsId: i,
code: Random.guid(),
title: Random.ctitle(4, 5),
commodity: "10010" + i,
goodsname: Random.cword(2, 6), // Random.csentence( min, max )
brand: Random.cword(2, 4),
sku: "1ml", // Random.dataImage( size, text ) 生成一段随机的 Base64 图片编码
inventory: Random.integer(10, 100),
number: Random.integer(100, 5000), //100到5000的随机整数
costPrice: Random.integer(10, 20),
amount: Random.integer(100, 200), //100到5000的随机整数
itemEdit: false,
ItemData: [{
address: Random.city(true),
email: Random.email(),
state: Random.boolean(),
salenumber: Random.integer(10, 100),
receivable: Random.integer(10, 100),
}, ],
};
orderList.push(item);
}
return {
total: 60,
data: obj.size == 10 ? orderList.slice(obj.size * obj.page - obj.size, obj.size * obj.page) : orderList,
};
};
export const homeList = (options) => {
let homeList = [];
for (let index = 0; index < 10; index++) {
let obj = {
name: "限时秒杀",
title_id: Random.integer(0, 10) + "id",
type: Random.boolean(),
number: Random.integer(10, 100),
order_number: Random.integer(100, 1000),
GWV_number: Random.integer(100, 5000),
state: Random.boolean(),
};
homeList.push(obj);
}
return {
data: homeList,
};
};
export const noticeLists = (options) => {
let noticeLists = [];
for (let index = 0; index < 10; index++) {
let item = {
text: Random.csentence(),
};
noticeLists.push(item);
}
return {
data: noticeLists,
};
};
export const cardlists = (options) => {
let obj = JSON.parse(options.body);
let cardlists = [];
for (let i = 0; i < 50; i++) {
let item = {
title: Random.csentence(5, 8), // Random.csentence( min, max )
user_name: Random.cname(), // Random.cname() 随机生成一个常见的中文姓名
email: Random.email(),
number: '$' + Random.integer(100, 5000) + '.00',
date: Random.date(),
pay_state: '100' + Random.integer(1, 3),
content: Random.csentence(),
};
cardlists.push(item);
}
return {
data: cardlists,
};
};
+412 -183
View File
@@ -28,209 +28,98 @@ const routerList = [
},
],
},
{
path: "/form",
name: "form",
component: Layout,
meta: {
name: "表单页",
},
children: [
{
path: "/baseForm",
name: "baseForm",
component: () => import("../views/form/baseForm.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "基础表单",
},
},
{
path: "/stepFrom",
name: "stepFrom",
component: () => import("../views/form/stepFrom.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "分页表单",
},
},
{
path: "/advancedForm",
name: "advancedForm",
component: () => import("../views/form/advancedForm.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "高级表单",
},
},
],
},
{
path: "/system",
component: Layout,
name: "system",
meta: {
name: "系统配置",
requiresAuth: true, //有一些页面是否登录才能进去
},
children: [
{
path: "/homeSite",
name: "homesite",
component: () => import("../views/system/homeSite.vue"),
meta: {
name: "小程序首页",
requiresAuth: true, //有一些页面是否登录才能进去
},
},
{
path: "/customer",
name: "customer",
component: () => import("../views/system/customer.vue"),
meta: {
name: "客服电话",
requiresAuth: true, //有一些页面是否登录才能进去
},
},
{
path: "/activity",
name: "activity",
component: () => import("../views/system/activity.vue"),
meta: {
name: "活动管理",
requiresAuth: true, //有一些页面是否登录才能进去
},
},
{
path: "/switchOrder",
name: "switchOrder",
component: () => import("../views/system/switchOrder.vue"),
meta: {
name: "重复下单开关",
requiresAuth: true, //有一些页面是否登录才能进去
},
},
{
path: "/edit",
name: "edit",
component: () => import("../views/system/edit.vue"),
meta: {
name: "编辑资料",
requiresAuth: true, //有一些页面是否登录才能进去
},
},
],
},
{
path: "/goods",
component: Layout,
redirect: "goods",
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "服务项目",
},
children: [
{
path: "/goods",
name: "goods",
component: () => import("../views/goods/index.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "服务项目",
},
},
],
},
{
path: "/order",
component: Layout,
redirect: "order",
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "订单",
},
children: [
{
path: "/order",
name: "order",
component: () => import("../views/order/index.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "订单列表",
},
},
],
},
{
path: "/users",
name: "users",
component: Layout,
meta: {
name: "客户",
name: "系统管理",
},
children: [
{
path: "/index",
name: "index",
component: () => import("../views/users/index.vue"),
path: "/Department",
name: "Department",
component: () => import("../views/system/Department/index.vue"),
meta: {
requiresAuth: true,
name: "客户列表",
requiresAuth: true, //有一些页面是否登录才能进去
name: "基础表格",
},
},
{
path: "/reconnaissanceList",
name: "reconnaissanceList",
component: () => import("../views/users/reconnaissance.vue"),
path: "/UserList",
name: "UserList",
component: () => import("../views/system/UserList/index.vue"),
meta: {
requiresAuth: true,
name: "勘测工程师",
requiresAuth: true, //有一些页面是否登录才能进去
name: "内嵌表格",
},
},
{
path: "/maintainList",
name: "maintainList",
component: () => import("../views/users/maintain.vue"),
path: "/RoleList",
name: "RoleList",
component: () => import("../views/system/RoleList/index.vue"),
meta: {
requiresAuth: true,
name: "维修人员",
name: "滑动加载",
},
},
{
path: "/MenuList",
name: "MenuList",
component: () => import("../views/system/MenuList/index.vue"),
meta: {
requiresAuth: true,
name: "可编辑Table",
},
},
{
path: "/importExcel",
name: "importExcel",
component: () => import("../views/system/Excel/importExcel.vue"),
meta: {
requiresAuth: true,
name: "Excel",
},
},
],
},
{
path: "/engineer",
component: Layout,
name: "engineer",
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "工程师审核",
},
children: [
{
path: "/reconnaissance",
name: "reconnaissance",
component: () => import("../views/engineer/reconnaissance.vue"),
meta: {
requiresAuth: true,
name: "勘测工程师审核",
},
},
{
path: "/maintain",
name: "maintain",
component: () => import("../views/engineer/maintain.vue"),
meta: {
requiresAuth: true,
name: "维修人员审核",
},
},
],
},
{
path: "/scheduling",
component: Layout,
name: "scheduling",
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "工程师审核",
},
children: [
{
path: "/timeFrame",
name: "timeFrame",
component: () => import("../views/scheduling/timeFrame.vue"),
meta: {
requiresAuth: true,
name: "排班时段",
},
},
{
path: "/reconnaissanceScheduling",
name: "reconnaissanceScheduling",
component: () => import("../views/scheduling/reconnaissance.vue"),
meta: {
requiresAuth: true,
name: "勘测人员排班",
},
},
{
path: "/maintainScheduling",
name: "maintainScheduling",
component: () => import("../views/scheduling/maintain.vue"),
meta: {
requiresAuth: true,
name: "维修人员排班",
},
},
],
},
{
path: "/ErrorMessage",
name: "ErrorMessage",
@@ -259,7 +148,347 @@ const routerList = [
},
],
},
{
path: "/goods",
name: "goods",
component: Layout,
meta: {
name: "列表页",
},
children: [
{
path: "/goodCategory",
name: "goodCategory",
component: () => import("../views/goods/goodCategory.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "基础列表",
},
},
{
path: "/cardList",
name: "cardList",
component: () => import("../views/goods/cardList.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "卡片列表",
},
},
{
path: "/searchList",
name: "searchList",
component: () => import("../views/goods/searchList.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "搜索列表",
},
},
],
},
{
path: "/able",
name: "able",
component: Layout,
meta: {
name: "功能",
},
children: [
{
path: "/watermark",
name: "watermark",
component: () => import("../views/able/watermark.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "水印",
},
},
{
path: "/countTo",
name: "countTo",
component: () => import("../views/able/countTo.vue"),
meta: {
requiresAuth: true, //有一些页面是否登录才能进去
name: "数字动画",
},
},
{
path: "/batchImport",
name: "batchImport",
component: () => import("../views/able/batchImport.vue"),
meta: {
requiresAuth: true,
name: "图片上传",
},
},
{
path: "/fileImport",
name: "fileImport",
component: () => import("../views/able/fileImport.vue"),
meta: {
requiresAuth: true,
name: "文件上传",
},
},
{
path: "/wangEditor",
name: "wangEditor",
component: () => import("../views/able/wangEditor.vue"),
meta: {
requiresAuth: true,
name: "富文本编辑器",
},
},
{
path: "/markdown",
name: "markdown",
component: () => import("../views/able/markdown.vue"),
meta: {
requiresAuth: true,
name: "markdown",
},
},
{
path: "/strength",
name: "strength",
component: () => import("../views/able/strength.vue"),
meta: {
requiresAuth: true,
name: "密码强度",
},
},
{
path: "/validation",
name: "validation",
component: () => import("../views/able/validation.vue"),
meta: {
requiresAuth: true,
name: "验证组件",
},
},
{
path: "/guide",
name: "guide",
component: () => import("../views/able/guide.vue"),
meta: {
requiresAuth: true,
name: "引导页",
},
},
{
path: "/embedded",
name: "embedded",
component: () => import("../views/able/embedded.vue"),
meta: {
requiresAuth: true,
name: "内嵌页",
},
},
],
},
{
path: "/flow",
name: "flow",
component: Layout,
meta: {
name: "图形编辑器",
},
children: [
{
path: "/flowCat",
name: "flowCat",
component: () => import("../views/flow/flowCat.vue"),
meta: {
requiresAuth: true,
name: "流程图",
},
},
],
},
{
path: "/echarts",
name: "echarts",
component: Layout,
meta: {
name: "图表",
},
children: [
{
path: "/baidumap",
name: "baidumap",
component: () => import("../views/echarts/map/baidumap.vue"),
meta: {
requiresAuth: true,
name: "百度地图",
},
},
{
path: "/gaodemap",
name: "gaodemap",
component: () => import("../views/echarts/map/gaodemap.vue"),
meta: {
requiresAuth: true,
name: "高德地图",
},
},
{
path: "/histogram",
name: "histogram",
component: () => import("../views/echarts/histogram.vue"),
mate: {
requiresAuth: true,
name: "柱状图",
},
},
{
path: "/line",
name: "line",
component: () => import("../views/echarts/line.vue"),
meta: {
requiresAuth: true,
name: "折线图",
},
},
{
path: "/radar",
name: "radar",
component: () => import("../views/echarts/radar.vue"),
meta: {
requiresAuth: true,
name: "雷达图",
},
},
],
},
{
path: "/video",
name: "video",
component: Layout,
meta: {
name: "视频播放器",
},
children: [
{
path: "/video",
name: "video",
component: () => import("../views/video/index.vue"),
meta: {
requiresAuth: true,
name: "视频播放器",
},
},
],
},
{
path: "/DataReport",
name: "DataReport",
component: Layout,
meta: {
name: "数据统计",
},
children: [
{
path: "/demo1",
name: "demo1",
component: () => import("../views/DataReport/demo1.vue"),
meta: {
requiresAuth: true,
name: "项目一",
},
},
],
},
{
path: "/material",
name: "material",
component: Layout,
meta: {
name: "素材管理",
},
children: [
{
path: "/materialIndex",
name: "materialIndex",
component: () => import("../views/material/materialIndex.vue"),
meta: {
requiresAuth: true,
name: "素材管理",
},
},
],
},
{
path: "/directives",
name: "directives",
component: Layout,
meta: {
name: "自定义指令",
},
children: [
{
path: "/Drag",
name: "Drag",
component: () => import("../views/directives/Drag.vue"),
meta: {
requiresAuth: true,
name: "拖拽",
},
},
{
path: "/throttle",
name: "throttle",
component: () => import("../views/directives/throttle.vue"),
meta: {
requiresAuth: true,
name: "节流",
},
},
{
path: "/copy",
name: "copy",
component: () => import("../views/directives/copy.vue"),
meta: {
requiresAuth: true,
name: "复制",
},
},
{
path: "/debounceDirect",
name: "debounceDirect",
component: () => import("../views/directives/debounceDirect.vue"),
meta: {
requiresAuth: true,
name: "防抖",
},
},
{
path: "/longPress",
name: "longPress",
component: () => import("../views/directives/longPress.vue"),
meta: {
requiresAuth: true,
name: "长按指令",
},
},
],
},
{
path: "/users",
name: "users",
component: Layout,
meta: {
name: "个人中心",
},
children: [
{
path: "/user",
name: "user",
component: () => import("../views/users/index.vue"),
meta: {
requiresAuth: true,
name: "关于我",
},
},
],
},
];
export default routerList;
+6 -7
View File
@@ -8,7 +8,7 @@ export default {
state: {
UserInfo: {},
token: sessionStorage.getItem("token") || "",
isCollapse: false,
isCollapse: true,
themeConfig: {
primary: "#4060c7",
tabColor: "#FFFFFF",
@@ -63,12 +63,11 @@ export default {
return new Promise((resolve, reject) => {
LoginInfo(userInfo)
.then((res) => {
console.log(res.data.token, "token");
sessionStorage.setItem("token", res.data.token);
localStorage.setItem("token", res.data.token);
sessionStorage.setItem("UserInfo", JSON.stringify(res.data));
commit("setToken", res.data.token);
commit("setUserInfo", res.data);
console.log(res.data.data);
sessionStorage.setItem("token", res.data.data.token);
sessionStorage.setItem("UserInfo", JSON.stringify(res.data.data));
commit("setToken", res.data.data.token);
commit("setUserInfo", res.data.data);
router.replace("/");
ElMessage({
message: "登录成功",
+24
View File
@@ -0,0 +1,24 @@
<template>
<div class="content-box" style="height: 100%">
<iframe
src="http://124.221.156.158:3031/#/ScreenPage"
frameborder="0"
class="full-iframe"
></iframe>
</div>
</template>
<style lang="scss" scoped>
.content-box {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
background-color: #fff;
}
.full-iframe {
// margin-top: 2.5%;
width: 100%;
height: 100%;
}
</style>
View File
+1
View File
@@ -0,0 +1 @@
<template>数据统计</template>
+53
View File
@@ -0,0 +1,53 @@
<template>
<el-card class="box-card col-center" shadow="never">
<div class="box-card-title">图片上传 🍱🍱🍱🍱🍱</div>
<el-upload
v-model:file-list="fileList"
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
>
<el-icon><Plus /></el-icon>
</el-upload>
<el-image-viewer v-if="dialogVisible" @close="imageView" style="width: 100px; height: 100px" :url-list="[dialogImageUrl]" />
</el-card>
</template>
<script setup>
import { reactive, ref } from "vue";
import { Plus } from "@element-plus/icons-vue";
const dialogImageUrl = ref("");
const dialogVisible = ref(false);
const pictureUpload = ref(null);
const fileList = ref([]);
const handleRemove = (file) => {
console.log(file);
};
const imageView = () => {
dialogVisible.value = false;
};
const handlePictureCardPreview = (file) => {
console.log(file.url);
dialogImageUrl.value = file.url;
dialogVisible.value = true;
};
</script>
<style lang="scss" scoped>
.box-card {
width: 100%;
.box-card-title {
padding-bottom: 20px;
}
}
.el-image-viewer__canvas {
img {
width: 120px !important;
height: auto !important;
}
}
</style>
+75
View File
@@ -0,0 +1,75 @@
<template>
<el-card class="box-card col-center" shadow="never">
<div class="box-card-title">数字动画 🍝🍝🍝🍝</div>
<div class="number-grow-warp">
<span ref="numberGrow" :data-time="time" class="number-grow" :data-value="number">0</span>
</div>
</el-card>
</template>
<script setup>
/* 需求说明:
1.数字不需要千位符,但是为了防止以后要有 所以加了个参数判断,默认是没有的
2.数字整数变动
3.组件改为行内元素,能更好的兼容页面样式
4.第二次数字变动在上次的数字累加
5.添加监听器防止页面不更新的情况
*/
import { onMounted, reactive, ref, watch } from "vue";
const time = reactive(6000);
const thousandSign = ref(false);
const number = ref(997052786868686);
const oldValue = ref(6868686);
const numberGrow = ref(null);
const setNumberGrow = (ele) => {
let value = number.value - oldValue.value;
let step = (value * 10) / (time * 100);
let current = 0;
let start = oldValue.value;
let t = setInterval(function () {
start += step;
if (start > number.value) {
clearInterval(t);
start = number.value;
t = null;
}
if (current === start) {
return;
}
current = parseInt(start);
oldValue.value = current;
if (thousandSign.value) {
ele.innerHTML = current.toString().replace(/(\d)(?=(?:\d{3}[+]?)+$)/g, "$1,");
} else {
ele.innerHTML = current.toString();
}
}, 10);
};
watch(number.value, (newV, oldV) => {
setNumberGrow(numberGrow.value);
// gsap.to(this, { duration: 0.5, tweened: Number(n) || 0 });
});
// watch: {
// number(n) {
// gsap.to(this, { duration: 0.5, tweened: Number(n) || 0 })
// }
// }
onMounted(() => {
setNumberGrow(numberGrow.value);
});
</script>
<style lang="scss" scoped>
.box-card {
width: 100%;
.box-card-title {
margin-bottom: 20px;
}
}
.number-grow-warp {
transform: translateZ(0);
}
</style>
+20
View File
@@ -0,0 +1,20 @@
<template>
<div class="content-box" style="height: 100%">
<iframe src="https://cn.bing.com/" frameborder="0" class="full-iframe"></iframe>
</div>
</template>
<style lang="scss" scoped>
.content-box {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
background-color: #fff;
}
.full-iframe {
// margin-top: 2.5%;
width: 100%;
height: 100%;
}
</style>
+87
View File
@@ -0,0 +1,87 @@
<template>
<el-card class="box-card" shadow="never">
<div class="box-card-title">文件上传 🍱🍱🍱🍱🍱</div>
<el-upload
class="upload-demo"
drag
multiple
:show-file-list="true"
:limit="excelLimit"
:http-request="uploadExcel"
:before-upload="beforeExcelUpload"
:on-exceed="handleExceed"
:on-success="excelUploadSuccess"
:on-error="excelUploadError"
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处<em>或点击上传</em></div>
<template #tip>
<div class="el-upload__tip">请上传 .xls , .xlsx 标准格式文件</div>
</template>
</el-upload>
</el-card>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { ElNotification } from 'element-plus'
// 最大文件数
const excelLimit = ref(1)
// 文件上传
const uploadExcel = (param) => {}
const beforeExcelUpload = (file) => {
const isExcel =
file.type === 'application/vnd.ms-excel' ||
file.type ===
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
const isLt5M = file.size / 1024 / 1024 < 5
if (!isExcel)
ElNotification({
message: '上传文件只能是 xls / xlsx 格式!',
type: 'warning',
})
if (!isLt5M)
ElNotification({
message: '上传文件大小不能超过 5MB!',
type: 'warning',
})
return isExcel && isLt5M
}
// 文件数超出提示
const handleExceed = () => {
ElNotification({
message: '最多只能上传一个文件!',
type: 'warning',
})
}
// 上传错误提示
const excelUploadError = () => {
ElNotification({
message: '导入数据失败,请您重新上传!',
type: 'error',
})
}
// 上传成功提示
const excelUploadSuccess = () => {
ElNotification({
message: '导入数据成功!',
type: 'success',
})
}
</script>
<style lang="scss" scoped>
.box-card {
width: 100%;
.box-card-title {
padding-bottom: 20px;
}
}
.upload-demo {
width: 50%;
}
</style>
+61
View File
@@ -0,0 +1,61 @@
<template>
<el-card class="box-card col-center" shadow="never">
<div class="box-card-title">引导页 🍮🍯🍳🍔</div>
<el-button type="primary" @click.prevent.stop="guide">开启指引</el-button>
</el-card>
</template>
<script setup>
import Driver from "driver.js";
import "driver.js/dist/driver.min.css";
const guide = () => {
const driver = new Driver({
allowClose: false,
doneBtnText: "结束",
closeBtnText: "关闭",
nextBtnText: "下一步",
prevBtnText: "上一步",
});
driver.defineSteps(steps);
driver.start();
};
const steps = [
{
element: "#collapseIcon",
popover: {
title: "Collapse Icon",
description: "Open && Close sidebar",
position: "right",
},
},
{
element: "#breadcrumb",
popover: {
title: "Breadcrumb",
description: "Indicate the current page location",
position: "right",
},
},
{
element: "#fullscreen",
popover: {
title: "Full Screen",
description: "Full Screen, Exit The Full Screen Page",
position: "left",
},
},
];
</script>
<style lang="scss" scoped>
.box-card {
width: 100%;
.box-card-title {
margin-bottom: 20px;
}
}
</style>
+45
View File
@@ -0,0 +1,45 @@
const setWaterCanvas = (str1, color) => {
console.log(color);
const id = "1.23452384164.123412415";
if (document.getElementById(id) !== null) {
document.body.removeChild(document.getElementById(id));
}
const can = document.createElement("canvas");
can.width = 120;
can.height = 80;
const cans = can.getContext("2d");
cans.rotate((-20 * Math.PI) / 180); // 水印旋转角度
cans.font = "15px Vedana";
cans.fillStyle = color;
cans.textAlign = "center";
cans.textBaseline = "Middle";
cans.fillText(str1, can.width / 2, can.height);
const div = document.createElement("div");
div.id = id;
div.style.pointerEvents = "none";
div.style.top = "40px";
div.style.left = "0px";
div.style.opacity = "0.15";
div.style.position = "fixed";
div.style.zIndex = "100000";
div.style.width = document.documentElement.clientWidth + "px";
div.style.height = document.documentElement.clientHeight + "px";
div.style.background = "url(" + can.toDataURL("image/png") + ") left top repeat";
document.body.appendChild(div);
return id;
};
// 创建水印
export function setWatermark(str1, color) {
let id = setWaterCanvas(str1, color);
if (document.getElementById(id) === null) {
id = setWaterCanvas(str1, color);
}
}
// 清除水印
export function clear() {
const id = "1.23452384164.123412415";
if (document.getElementById(id) !== null) {
document.body.removeChild(document.getElementById(id));
}
}
+24
View File
@@ -0,0 +1,24 @@
<template>
<el-card>
<div class="card-title">markdown编辑器🍬🍬🍬🍭🍭🍭<span @click="gotoUrl">[文档链接]</span></div>
<v-md-editor model="text" height="80vh"></v-md-editor>
</el-card>
</template>
<script setup>
import { ref } from "vue";
const text = ref("");
const gotoUrl = () => {
window.open("https://ckang1229.gitee.io/vue-markdown-editor/zh/#%E4%BB%8B%E7%BB%8D", "_blank");
};
</script>
<style lang="scss" scoped>
.card-title {
padding-bottom: 10px;
font-size: 18px;
font-weight: bold;
span {
color: #673ab7;
cursor: pointer;
}
}
</style>
+84
View File
@@ -0,0 +1,84 @@
<template>
<el-card :shadow="never" class="col-center">
<div class="p10">密码强度🍓🍇🍈🍉</div>
<el-form
label-position="left"
label-width="100px"
:model="formLabelAlign"
style="width: 460px"
>
<el-form-item label="请输入密码">
<el-input
v-model="formLabelAlign.passsword"
:prefix-icon="Lock"
type="password"
show-password
/>
</el-form-item>
<el-form-item label="密码强度">
<el-progress
v-show="formLabelAlign.passsword"
:percentage="percentage"
style="width: 460px"
:status="status"
/>
</el-form-item>
</el-form>
</el-card>
</template>
<script setup>
import { reactive, ref, watch } from 'vue'
const formLabelAlign = reactive({
passsword: '',
})
let percentage = ref(0)
let status = ref('exception')
const checkStrong = (sValue) => {
var modes = 0
if (sValue.length < 1) return modes
if (/\d/.test(sValue)) modes++ //数字
if (/[a-z]/.test(sValue)) modes++ //小写
if (/[A-Z]/.test(sValue)) modes++ //大写
if (/\W/.test(sValue)) modes++ //特殊字符
switch (modes) {
case 1:
return 1
break
case 2:
return 2
break
case 3:
case 4:
return sValue.length < 10 ? 3 : 4
break
}
return modes
}
const statusChange = (modes) => {
if (modes == 1) {
percentage.value = 25
status.value = 'exception'
} else if (modes == 2) {
percentage.value = 50
status.value = 'exception'
} else if (modes == 3) {
percentage.value = 75
status.value = 'warning'
} else {
percentage.value = 100
status.value = 'success'
}
}
watch(
() => formLabelAlign.passsword,
(newValue, oldValue) => {
let modes = checkStrong(newValue)
console.log(modes)
statusChange(modes)
}
)
</script>
+278
View File
@@ -0,0 +1,278 @@
<template>
<el-card class="clo-center">
<div class="p10">验证组件🍨🍨🍨🍧🍧🍧</div>
<el-form label-position="left" inline label-width="100px" :model="formLabelAlign">
<el-form-item label="请输入验证码" style="margin-right: 0">
<el-input v-model="formLabelAlign.code" />
</el-form-item>
<el-form-item>
<div class="s-canvas">
<canvas @click="upDataCode" ref="canvasRef" :width="contentWidth" :height="contentHeight"></canvas></div
></el-form-item>
</el-form>
<div className="sliderContent">
<div className="imgDev" style="width: 500px">
<canvas id="canvasImg" width="500" height="auto"></canvas>
<canvas className="slider" id="sliderBlock" :width="500" :height="280" :style="{ left: sildLeft + 'px' }"></canvas>
<!-- <el-slider class="moveSlider" @change="changeValue1" v-model="value1" /> -->
</div>
</div>
<div class="moveSlider" :style="{ background: verifyResult ? '#859baa' : '#f7f8fa', color: verifyResult ? '#fff' : '606266' }">
{{ verifyResult ? "解锁成功" : "滑动解锁" }}
<div class="slider" @mousedown="sliderMove" ref="slider">
<el-icon v-if="verifyResult" class="icon-style" style="color: #859baa"><Select /></el-icon>
<el-icon v-else class="icon-style"><DArrowRight /></el-icon>
</div>
</div>
</el-card>
</template>
<script setup>
import { DArrowRight, Select } from "@element-plus/icons-vue";
import { onMounted, reactive, ref } from "vue";
const contentWidth = ref(100);
const contentHeight = ref(32);
const sliderWidth = ref();
const sliderHeight = ref();
const sildLeft = ref(0);
const value1 = ref(0);
const sildY = ref();
const sildX = ref();
const verifyResult = ref(false);
const formLabelAlign = reactive({
code: "",
});
const identifyCodes = ref("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
const identifyCode = ref("1234");
const canvasRef = ref(null);
// 生成随机数
const randomNum = (min, max) => {
return Math.floor(Math.random() * (max - min) + min);
};
const randomColor = (min, max) => {
var r = randomNum(min, max);
var g = randomNum(min, max);
var b = randomNum(min, max);
return "rgb(" + r + "," + g + "," + b + ")";
};
const drawPic = () => {
let ctx = canvasRef.value.getContext("2d");
ctx.fillStyle = randomColor(180, 230); //填充颜色
ctx.fillRect(0, 0, contentWidth.value, contentHeight.value); //填充位置
// drawLine(ctx);
let imgCode = "";
// 随机产生字符串,并且随机旋转
for (let i = 0; i < 4; i++) {
const text = identifyCodes.value[randomNum(0, identifyCodes.value.length)];
const deg = randomNum(-30, 30);
imgCode += text;
ctx.font = randomNum(18, 40) + "px Simhei"; //填充字体
ctx.textBaseline = "top";
ctx.fillStyle = randomColor(80, 150);
drawDot(ctx);
ctx.save(); //保存
ctx.translate(30 * i + 15, 15);
ctx.rotate((deg * Math.PI) / 180); //随机的旋转
ctx.fillText(text, -15 + 5, -15); //
ctx.restore(); //清除
}
drawLine(ctx);
return imgCode;
};
const drawLine = (ctx) => {
for (let i = 0; i < 5; i++) {
ctx.strokeStyle = randomColor(0, 255);
ctx.beginPath();
ctx.moveTo(randomNum(0, contentWidth.value), randomNum(0, contentHeight.value));
ctx.lineTo(randomNum(0, contentWidth.value), randomNum(0, contentHeight.value));
ctx.stroke();
}
};
const drawDot = (ctx) => {
for (let i = 0; i < 20; i++) {
ctx.fillStyle = randomColor(0, 255);
ctx.beginPath();
ctx.arc(randomNum(0, contentWidth.value), randomNum(0, contentHeight.value), 1, 0, 2 * Math.PI);
ctx.fill();
}
};
onMounted(() => {
drawPic();
loadImage();
});
const upDataCode = () => {
identifyCode.value = "";
makeCode(identifyCodes.value, 4);
};
const makeCode = (val, l) => {
for (let i = 1; i < val.length && i <= l; i++) {
identifyCode.value += identifyCodes.value[Math.floor(Math.random() * (identifyCodes.value.length - 0) + 0)];
}
console.log(identifyCode.value);
drawPic();
};
// 拼图
const loadImage = () => {
//加载图片
let mainDom = document.getElementById("canvasImg");
let bg = mainDom.getContext("2d");
let imgSrc =
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F202001%2F30%2F20200130003214_3GJWF.jpeg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1663755123&t=0f35d18b29de642d5af549a5ec7062e5";
let img = document.createElement("img");
img.src = imgSrc;
img.onload = () => {
mainDom.height = (img.height / img.width) * mainDom.width;
bg.drawImage(img, 0, 0, mainDom.width, mainDom.height);
let r = 10; //半圆的半径
let w = 60; //滑块的宽度
let x = randomNum(85, mainDom.width - w - r - 2); //保证缺口完全展示,不会隐藏
let y = randomNum(16, mainDom.height - w - r - 2);
sildY.value = y;
sildX.value = x;
bg.lineWidth = 1;
bg.strokeStyle = "white";
bg.beginPath();
bg.moveTo(x, y);
//top
bg.arc(x + w / 2, y, r, -Math.PI, 0, true);
bg.lineTo(x + w, y);
//right
bg.arc(x + w, y + w / 2, r, 1.5 * Math.PI, 0.5 * Math.PI, false);
bg.lineTo(x + w, y + w);
//bottom
bg.arc(x + w / 2, y + w, r, 0, Math.PI, false);
bg.lineTo(x, y + w);
//left
bg.arc(x, y + w / 2, r, 0.5 * Math.PI, 1.5 * Math.PI, true);
bg.lineTo(x, y);
bg.stroke();
bg.fillStyle = "rgba(0, 0, 0, 0.4)"; //设置背景颜色
bg.fill();
sliderContent(img);
};
};
const sliderContent = (img) => {
let r = 10; //半圆的半径
let w = 60; //滑块的宽度
let mainDom = document.getElementById("sliderBlock");
let ctx = mainDom.getContext("2d");
//index.store.ts
let x = sildLeft.value;
let y = sildY.value;
let PI = Math.PI;
ctx.lineWidth = 1;
//绘制
ctx.beginPath();
//left
ctx.moveTo(x, y);
//top
ctx.arc(x + w / 2, y, r, -PI, 0, true);
ctx.lineTo(x + w, y);
//right
ctx.arc(x + w, y + w / 2, r, 1.5 * PI, 0.5 * PI, false);
ctx.lineTo(x + w, y + w);
//bottom
ctx.arc(x + w / 2, y + w, r, 0, PI, false);
ctx.lineTo(x, y + w);
//left
ctx.arc(x, y + w / 2, r, 0.5 * PI, 1.5 * PI, true);
ctx.lineTo(x, y);
ctx.shadowBlur = 10;
ctx.shadowColor = "black";
ctx.stroke();
ctx.clip();
console.log(img);
ctx.drawImage(img, -sildX.value + sildLeft.value, 0, 500, 280);
// console.log(ctx)
};
const sliderMove = (event) => {
let disX = 0;
const iconWidth = 60;
const ele = document.querySelector(".moveSlider .slider");
const startX = event.clientX || event.touches[0].pageX;
const MaxX = 500 - iconWidth;
if (verifyResult.value) {
return false;
}
// 开始移动
const onMove = (e) => {
const endX = e.clientX || e.touches[0].pageX;
disX = endX - startX;
if (disX <= 0) {
disX = 0;
}
if (disX >= MaxX - iconWidth) {
disX = MaxX;
}
sildLeft.value = disX;
ele.style.transition = ".1s all";
ele.style.transform = `translateX(${disX}px)`;
console.log(ele.style.transform);
};
const onEnd = () => {
if (disX > sildX.value - 5 && disX < sildX.value + 5) {
verifyResult.value = true;
} else {
ele.style.transition = ".5s all";
ele.style.transform = "translateX(0)";
}
document.removeEventListener("mousemove", onMove);
document.removeEventListener("mouseup", onEnd);
};
document.addEventListener("mousemove", onMove);
document.addEventListener("mouseup", onEnd);
};
</script>
<style lang="scss" scoped>
.s-canvas {
height: 38px;
}
.s-canvas canvas {
margin-top: 1px;
margin-left: 8px;
}
.sliderContent {
margin-top: 20px;
position: relative;
.slider {
position: absolute;
}
}
.moveSlider {
width: 500px;
height: 32px;
background-color: #f7f8fa;
font-size: 14px;
line-height: 32px;
text-align: center;
color: #606266;
position: relative;
border: 1px solid #e4e7ed;
.slider {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 32px;
background-color: #fff;
cursor: pointer;
.icon-style {
margin-top: 6px;
font-size: 20px;
text-align: center;
}
}
}
</style>
+66
View File
@@ -0,0 +1,66 @@
<template>
<el-card class="box-card col-center" shadow="never">
<span class="box-card-title">富文本编辑器 🍰🍰🍰🍩🍩🍩</span>
<div class="wangeditor-box">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
class="editor-txt"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
/>
</div>
</el-card>
</template>
<script setup>
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
const editorRef = shallowRef()
// 内容 HTML
const valueHtml = ref('<p>hello</p>')
// 模拟 ajax 异步获取内容
onMounted(() => {
setTimeout(() => {
valueHtml.value = '<p>富文本编辑器</p>'
}, 1500)
})
const toolbarConfig = {}
const editorConfig = { placeholder: '请输入内容...' }
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
const handleCreated = (editor) => {
editorRef.value = editor // 记录 editor 实例,重要!
}
</script>
<style lang="scss" scoped>
.box-card {
width: 100%;
.wangeditor-box {
border: 1px solid #f0f2f5;
margin-top: 20px;
}
.editor-txt {
height: 75vh !important;
overflow-y: hidden;
text-align: left;
}
}
</style>
+49
View File
@@ -0,0 +1,49 @@
<template>
<el-row>
<el-col>
<el-card shadow="never">
<div class="p10">水印组件🍬🍬🍬🍭🍭🍭</div>
<el-form :inline="true" ref="formRef" :model="numberValidateForm" label-width="100px" class="demo-ruleForm">
<el-form-item
label="水印名称"
prop="text"
:rules="[
{ required: true, message: 'age is required' },
{ type: 'text', message: '请输入水印名称' },
]"
>
<el-input v-model="numberValidateForm.text" type="text" autocomplete="off" />
</el-form-item>
<el-form-item label="选择水印颜色" prop="color">
<el-color-picker v-model="numberValidateForm.color" show-alpha />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(formRef)">创建</el-button>
<el-button @click="resetForm(formRef)">取消</el-button>
</el-form-item>
</el-form>
</el-card>
</el-col>
</el-row>
</template>
<script setup>
import { reactive } from "vue";
import { setWatermark, clear } from "./index.js";
const numberValidateForm = reactive({
text: "",
color: "#4060c7",
});
const submitForm = () => {
console.log(numberValidateForm.color);
setWatermark(numberValidateForm.text, numberValidateForm.color);
};
const resetForm = () => {
numberValidateForm.text = "";
numberValidateForm.color = "";
clear();
};
</script>
+1
View File
@@ -0,0 +1 @@
<template>关于我</template>
+39
View File
@@ -0,0 +1,39 @@
<template>
<el-card>
<span class="box-card-title">拖拽🍻🍻🍻🍵🍵🍵</span>
<div class="box-card-content">
<div v-draggable class="drag-box flx-center text">我可以拖拽哦~</div>
<div
v-draggable
class="drag-box flx-center text"
style="background: #eba300; width: 200px; height: 200px"
>
我可以拖拽哦~
</div>
</div>
</el-card>
</template>
<script setup></script>
<style lang="scss" scoped>
.box-card-title {
padding: 10px;
// display: block;
}
.box-card-content {
width: 100%;
height: 80vh;
background-color: #fff;
position: relative;
.drag-box {
position: absolute;
top: 110px;
width: 300px;
height: 300px;
color: #fff;
background: #bad80a;
}
}
</style>
+17
View File
@@ -0,0 +1,17 @@
<template>
<el-card shadow="never">
<div>复制指令 🍤🍤🍤🍤🍤🍤</div>
<br />
<el-input v-model="input3" placeholder="复制指令 🍤🍤🍤🍤🍤" style="width: 100%">
<template #append>
<el-button :icon="CopyDocument" v-copy="input3">复制</el-button>
</template>
</el-input>
</el-card>
</template>
<script setup>
import { ref } from "vue";
import { CopyDocument } from "@element-plus/icons-vue";
const input3 = ref("复制内容复制内容复制内容复制内容复制内容");
</script>
+14
View File
@@ -0,0 +1,14 @@
<template>
<el-card shadow="never">
<div class="card-title">防抖指令 🍍🍓🍓🍓🍓</div>
<br />
<el-button type="primary" v-debounce="debounceClick">防抖按钮(1秒后执行)</el-button>
</el-card>
</template>
<script setup>
import { ElMessage } from "element-plus";
const debounceClick = () => {
ElMessage.success("我是防抖指令");
};
</script>
+14
View File
@@ -0,0 +1,14 @@
<template>
<el-card shadow="never">
<div class="card-title">长按指令 🍍🍓🍓🍓🍓</div>
<br />
<el-button type="primary" v-longPress="debounceClick">长按指令</el-button>
</el-card>
</template>
<script setup>
import { ElMessage } from "element-plus";
const debounceClick = () => {
ElMessage.success("我是长按指令");
};
</script>
+14
View File
@@ -0,0 +1,14 @@
<template>
<el-card shadow="never">
<div class="card-title">节流指令 🍍🍓🍓🍓🍓</div>
<br />
<el-button type="primary" v-throttle="throttleClick">节流指令</el-button>
</el-card>
</template>
<script setup>
import { ElMessage } from 'element-plus'
const throttleClick = () => {
ElMessage.success('我是节流指令')
}
</script>
+163
View File
@@ -0,0 +1,163 @@
<template>
<el-card style="height: 85vh">
<div id="histogram" style="width: 100%; height: 80vh"></div>
</el-card>
</template>
<script setup>
import * as echarts from 'echarts'
import { onMounted } from 'vue'
const getHistorgram = () => {
document.getElementById('histogram').setAttribute('_echarts_instance_', '')
var chartDom = document.getElementById('histogram')
var myChart = echarts.init(chartDom)
let app = {}
var option
const categories = (function () {
let now = new Date()
let res = []
let len = 10
while (len--) {
res.unshift(now.toLocaleTimeString().replace(/^\D*/, ''))
now = new Date(+now - 2000)
}
return res
})()
const categories2 = (function () {
let res = []
let len = 10
while (len--) {
res.push(10 - len - 1)
}
return res
})()
const data = (function () {
let res = []
let len = 10
while (len--) {
res.push(Math.round(Math.random() * 1000))
}
return res
})()
const data2 = (function () {
let res = []
let len = 0
while (len < 10) {
res.push(+(Math.random() * 10 + 5).toFixed(1))
len++
}
return res
})()
option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#283b56',
},
},
},
// legend: {},
// toolbox: {
// show: true,
// feature: {
// dataView: { readOnly: false },
// restore: {},
// saveAsImage: {},
// },
// },
dataZoom: {
show: false,
start: 0,
end: 100,
},
xAxis: [
{
type: 'category',
boundaryGap: true,
data: categories,
},
{
type: 'category',
boundaryGap: true,
data: categories2,
},
],
yAxis: [
{
type: 'value',
scale: true,
name: '价格',
max: 30,
min: 0,
boundaryGap: [0.2, 0.2],
},
{
type: 'value',
scale: true,
name: '订单数',
max: 1200,
min: 0,
boundaryGap: [0.2, 0.2],
},
],
series: [
{
name: 'Dynamic Bar',
type: 'bar',
xAxisIndex: 1,
yAxisIndex: 1,
data: data,
},
{
name: 'Dynamic Line',
type: 'line',
data: data2,
},
],
}
app.count = 11
setInterval(function () {
let axisData = new Date().toLocaleTimeString().replace(/^\D*/, '')
data.shift()
data.push(Math.round(Math.random() * 1000))
data2.shift()
data2.push(+(Math.random() * 10 + 5).toFixed(1))
categories.shift()
categories.push(axisData)
categories2.shift()
categories2.push(app.count++)
myChart.setOption({
xAxis: [
{
data: categories,
},
{
data: categories2,
},
],
series: [
{
data: data,
},
{
data: data2,
},
],
})
}, 2100)
option && myChart.setOption(option)
window.onresize = () => {
myChart.resize()
}
}
onMounted(() => {
setTimeout(() => {
getHistorgram()
}, 1000)
})
</script>
+88
View File
@@ -0,0 +1,88 @@
<template>
<el-card style="height: 85vh">
<div id="line" style="width: 100%; height: 80vh"></div>
</el-card>
</template>
<script setup>
import * as echarts from 'echarts'
import { onMounted } from 'vue'
const getHistorgram = () => {
document.getElementById('line').setAttribute('_echarts_instance_', '')
var chartDom = document.getElementById('line')
var myChart = echarts.init(chartDom)
let app = {}
var option = {
tooltip: {
trigger: 'axis',
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} °C',
},
},
series: [
{
name: 'Highest',
type: 'line',
data: [10, 11, 13, 11, 12, 12, 9],
markPoint: {
data: [
{ type: 'max', name: 'Max' },
{ type: 'min', name: 'Min' },
],
},
markLine: {
data: [{ type: 'average', name: 'Avg' }],
},
},
{
name: 'Lowest',
type: 'line',
data: [1, -2, 2, 5, 3, 2, 0],
markPoint: {
data: [{ name: '周最低', value: -2, xAxis: 1, yAxis: -1.5 }],
},
markLine: {
data: [
{ type: 'average', name: 'Avg' },
[
{
symbol: 'none',
x: '90%',
yAxis: 'max',
},
{
symbol: 'circle',
label: {
position: 'start',
formatter: 'Max',
},
type: 'max',
name: '最高点',
},
],
],
},
},
],
}
option && myChart.setOption(option)
window.onresize = () => {
myChart.resize()
}
}
onMounted(() => {
setTimeout(() => {
getHistorgram()
}, 1000)
})
</script>
+40
View File
@@ -0,0 +1,40 @@
<template>
<el-card>
<div id="container">111</div>
</el-card>
</template>
<script setup>
import { onMounted } from "vue";
const initMap = () => {
var map = new BMapGL.Map("container"); // 创建地图实例
var point = new BMapGL.Point(116.404, 39.915); // 创建点坐标
var marker = new BMapGL.Marker(point); // 创建标注
map.addOverlay(marker);
map.centerAndZoom(point, 15); // 初始化地图,设置中心点坐标和地图级别
map.enableScrollWheelZoom(true);
var scaleCtrl = new BMapGL.ScaleControl(); // 添加比例尺控件
map.addControl(scaleCtrl);
var zoomCtrl = new BMapGL.ZoomControl(); // 添加缩放控件
map.addControl(zoomCtrl);
var cityCtrl = new BMapGL.CityListControl(); // 添加城市列表控件
map.addControl(cityCtrl);
map.addEventListener("click", function (e) {
// 拿到点击地图上这一点的经纬度
// alert(e.point.lng + ", " + e.point.lat);
// 让地图中心平滑移动到点击的点
map.panTo(new BMap.Point(e.point.lng, e.point.lat));
});
};
onMounted(() => {
// initMap();
});
</script>
<style lang="scss" scoped>
#container {
width: 100%;
height: 85vh;
}
</style>
+44
View File
@@ -0,0 +1,44 @@
<template>
<el-card>
<div id="gaodeMap">111</div>
</el-card>
</template>
<script setup>
import { nextTick, onMounted } from "vue";
const initGaoMap = () => {
var map = new AMap.Map("gaodeMap", {
zoom: 11, //级别
center: [116.397428, 39.90923], //中心点坐标
viewMode: "2D", //使用3D视图
});
// 在图面添加工具条控件,工具条控件集成了缩放、平移、定位等功能按钮在内的组合控件
map.addControl(new AMap.ToolBar());
// 在图面添加比例尺控件,展示地图在当前层级和纬度下的比例尺
map.addControl(new AMap.Scale());
// 在图面添加鹰眼控件,在地图右下角显示地图的缩略图
map.addControl(new AMap.HawkEye({ isOpen: true }));
// 在图面添加类别切换控件,实现默认图层与卫星图、实施交通图层之间切换的控制
// map.addControl(new AMap.MapType())
// 在图面添加定位控件,用来获取和展示用户主机所在的经纬度位置
// map.addControl(new AMap.Geolocation())
map.setFitView();
};
onMounted(() => {
nextTick(() => {
// initGaoMap()
});
});
</script>
<style lang="scss" scoped>
#gaodeMap {
width: 100%;
height: 85vh;
}
</style>
+70
View File
@@ -0,0 +1,70 @@
<template>
<el-card style="height: 85vh">
<div id="radar" style="width: 100%; height: 80vh"></div>
</el-card>
</template>
<script setup>
import * as echarts from 'echarts'
import { onMounted } from 'vue'
const getHistorgram = () => {
document.getElementById('radar').setAttribute('_echarts_instance_', '')
var chartDom = document.getElementById('radar')
var myChart = echarts.init(chartDom)
let app = {}
var option = {
color: ['#33ccff ', '#ff99cc'],
radar: {
// shape: 'circle',
indicator: [
{ name: '体重', max: 6500 },
{ name: '打败', max: 16000 },
{ name: '完成目标', max: 30000 },
{ name: '身体年龄', max: 38000 },
{ name: '运动量', max: 52000 },
// { name: 'Marketing', max: 25000 },
],
},
series: [
{
name: 'Budget vs spending',
type: 'radar',
data: [
{
value: [4200, 3000, 20000, 35000, 50000, 18000],
name: 'Allocated Budget',
},
{
value: [5000, 14000, 28000, 26000, 42000, 21000],
name: 'Actual Spending',
areaStyle: {
color: new echarts.graphic.RadialGradient(0.1, 0.6, 1, [
{
color: 'rgba(255, 145, 124, 0.1)',
offset: 0,
},
{
color: '#ff99cc ',
offset: 1,
},
]),
},
},
],
},
],
}
option && myChart.setOption(option)
window.onresize = () => {
myChart.resize()
}
}
onMounted(() => {
setTimeout(() => {
getHistorgram()
}, 1000)
})
</script>
-305
View File
@@ -1,305 +0,0 @@
<template>
<!-- <el-card class="mt10">-->
<!-- <el-row>-->
<!-- <el-col :span="6">-->
<!-- <el-statistic title="合计" :value="268500" />-->
<!-- </el-col>-->
<!-- <el-col :span="6">-->
<!-- <el-statistic title="已通过" :value="268500" />-->
<!-- </el-col>-->
<!-- <el-col :span="6">-->
<!-- <el-statistic title="待审核" :value="268500" />-->
<!-- </el-col>-->
<!-- <el-col :span="6">-->
<!-- <el-statistic title="已驳回" :value="268500" />-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- </el-card>-->
<el-card class="mt10">
<el-form :inline="true" :model="formSearch" class="demo-form-inline">
<el-form-item label="姓名">
<el-input
v-model="formSearch.name"
style="max-width: 300px"
placeholder="模糊查询姓名"
class="input-with-select"
/>
</el-form-item>
<!-- <el-form-item label="手机号">-->
<!-- <el-input-->
<!-- v-model="searchWechatNickname"-->
<!-- style="max-width: 300px"-->
<!-- placeholder="模糊查询手机号"-->
<!-- class="input-with-select"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item label="时间">
<el-date-picker
v-model="formSearch.date"
type="date"
placeholder="请选择时间"
@clear="clearDate"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSearchSubmit">搜索</el-button>
</el-form-item>
</el-form>
<el-table
ref="table"
:data="tableData"
:default-sort="{ prop: 'date', order: 'descending' }"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
border
stripe
class="mt10"
>
<el-table-column
label="序号"
width="80"
align="center"
show-overflow-tooltip
sortable
>
<template #default="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="头像" width="200" align="center">
<template #default="scope">
<el-avatar :size="50" :src="scope.row.avatar" />
</template>
</el-table-column>
<el-table-column
label="名字"
prop="name"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="手机号"
prop="mobile"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="申请岗位"
prop="roleId"
:formatter="postFormater"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="申请时间"
prop="createTime"
width="auto"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column
label="状态"
prop="status"
:formatter="statusFormater"
width="auto"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column
label="操作"
fixed="right"
min-width="120"
>
<template v-slot:default="scope" >
<template v-if="scope.row.status === 0">
<el-button type="success" @click="handleApprove(scope.row)">通过</el-button>
<el-button type="danger" @click="handleReject(scope.row)">驳回</el-button>
</template>
<template v-else>
<el-tag type="info">处理完成</el-tag>
</template>
</template>
</el-table-column>
</el-table>
<el-pagination
size="small"
background
layout="prev, pager, next"
:total="tableData.length"
class="mt-4 mt10"
@current-change="handleCurrentChange"
/>
</el-card>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import {getApplyList, reject, approve} from "../../api/modules/postApply";
import { ElMessage, ElMessageBox } from 'element-plus'
const tableData = ref([]);
const total = ref(0)
const formSearch = ref({
roleId: 3,
name: '',
page: 1,
size: 10,
current: 1,
date: ''
});
const initData = () => {
getApplyList(formSearch.value).then((res) => {
tableData.value = res.data.records;
});
};
const formatDate = (date) => {
if (typeof date === 'string') {
// 检查是否已经是格式化的字符串
const regex = /^\d{4}-\d{2}-\d{2}$/;
if (regex.test(date)) {
return date; // 已经是格式化的字符串,直接返回
}
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
const statusFormater = (row, column, cellValue) => {
// 0待审核(审核中) 1驳回 2通过
if (cellValue === 1) {
return '已驳回';
} else if (cellValue === 2) {
return '已通过';
} else {
return '待审核';
}
}
const postFormater = (row, column, cellValue) => {
if (cellValue === 2) {
return '勘测工程师';
} else if (cellValue === 3) {
return '维修工程师';
} else {
return '工程师';
}
}
// 搜索事件
const onSearchSubmit = ()=> {
let params = {...formSearch.value}
if(params.date !== '')
{
params.date = formatDate(params.date);
}
getApplyList(params).then((res) => {
tableData.value = res.data.records
total.value = res.data.total
})
};
// 清空日期
const clearDate = () => {
formSearch.value.date = ''
}
const handleApprove = (item) => {
ElMessageBox.confirm('确定要通过该申请?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
approve(item.id).then(() => {
item.status = 2;
ElMessage({
type: 'success',
message: '审核完成'
})
})
}).catch(() => {
});
}
const handleReject = (item) => {
ElMessageBox.confirm('确定要拒绝该申请?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
reject(item.id).then(() => {
item.status = 1;
ElMessage({
type: 'success',
message: '驳回完成'
})
})
}).catch(() => {
});
}
// 驳回原因
const openModel = (index) => {
ElMessageBox.prompt('请输入驳回原因', '', {
confirmButtonText: '确认',
cancelButtonText: '取消',
inputType: 'textarea',
})
.then(({ value }) => {
// 用户确认后,调用 rejectApplication 函数
if (value) { // 确保用户输入了驳回原因
reject(applicationId, value);
} else {
ElMessage({
type: 'warning',
message: '请输入驳回原因',
});
}
})
.catch(() => {
// 用户取消操作,无需处理
});
};
const handleCurrentChange = (val) => {
formSearch.value.size = 10;
formSearch.value.page = val;
initData(formSearch.value);
};
onMounted(() => {
initData();
});
</script>
<style lang="scss" scoped>
.el-col {
text-align: center;
}
</style>
-326
View File
@@ -1,326 +0,0 @@
<template>
<!-- <el-card class="mt10">-->
<!-- <el-row>-->
<!-- <el-col :span="6">-->
<!-- <el-statistic title="合计" :value="268500" />-->
<!-- </el-col>-->
<!-- <el-col :span="6">-->
<!-- <el-statistic title="已通过" :value="268500" />-->
<!-- </el-col>-->
<!-- <el-col :span="6">-->
<!-- <el-statistic title="待审核" :value="268500" />-->
<!-- </el-col>-->
<!-- <el-col :span="6">-->
<!-- <el-statistic title="已驳回" :value="268500" />-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- </el-card>-->
<el-card class="mt10">
<el-form :inline="true" :model="formSearch" class="demo-form-inline">
<el-form-item label="姓名">
<el-input
v-model="formSearch.name"
style="max-width: 300px"
placeholder="模糊查询姓名"
class="input-with-select"
/>
</el-form-item>
<!-- <el-form-item label="手机号">-->
<!-- <el-input-->
<!-- v-model="searchWechatNickname"-->
<!-- style="max-width: 300px"-->
<!-- placeholder="模糊查询手机号"-->
<!-- class="input-with-select"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item label="时间">
<el-date-picker
v-model="formSearch.date"
type="date"
placeholder="请选择时间"
@clear="clearDate"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSearchSubmit">搜索</el-button>
</el-form-item>
</el-form>
<el-table
ref="table"
:data="tableData"
:default-sort="{ prop: 'date', order: 'descending' }"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
border
stripe
class="mt10"
>
<el-table-column
label="序号"
width="80"
align="center"
show-overflow-tooltip
sortable
>
<template #default="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="头像" width="200" align="center">
<template #default="scope">
<el-avatar :size="50" :src="scope.row.avatar" />
</template>
</el-table-column>
<el-table-column
label="名字"
prop="name"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="手机号"
prop="mobile"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="申请岗位"
prop="roleId"
:formatter="postFormater"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="申请时间"
prop="createTime"
width="auto"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column
label="状态"
prop="status"
:formatter="statusFormater"
width="auto"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column
label="操作"
fixed="right"
min-width="120"
>
<template v-slot:default="scope" >
<template v-if="scope.row.status === 0">
<el-button type="success" @click="handleApprove(scope.row)">通过</el-button>
<el-button type="danger" @click="handleReject(scope.row)">驳回</el-button>
</template>
<template v-else>
<el-tag type="info">处理完成</el-tag>
</template>
</template>
</el-table-column>
</el-table>
<el-pagination
size="small"
background
layout="prev, pager, next"
:total="tableData.length"
class="mt-4 mt10"
@current-change="handleCurrentChange"
/>
</el-card>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import {getApplyList, reject, approve} from "../../api/modules/postApply";
// 示例数据
// import {options} from './options.js'
// const exampleData = ref(JSON.parse(JSON.stringify(options)))
import { ElMessage, ElMessageBox } from 'element-plus'
const tableData = ref([]);
const searchWechatNickname = ref('');
const searchName = ref('');
const searchMobile = ref('');
const queryData = ref({
keyWord: '',
page: 1,
size: 10,
});
const total = ref(0)
const formSearch = ref({
roleId: 2,
name: '',
page: 1,
size: 10,
current: 1,
date: ''
});
const initData = () => {
getApplyList(formSearch.value).then((res) => {
tableData.value = res.data.records;
});
};
const formatDate = (date) => {
if (typeof date === 'string') {
// 检查是否已经是格式化的字符串
const regex = /^\d{4}-\d{2}-\d{2}$/;
if (regex.test(date)) {
return date; // 已经是格式化的字符串,直接返回
}
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
const statusFormater = (row, column, cellValue) => {
// 0待审核(审核中) 1驳回 2通过
if (cellValue === 1) {
return '已驳回';
} else if (cellValue === 2) {
return '已通过';
} else {
return '待审核';
}
}
const postFormater = (row, column, cellValue) => {
if (cellValue === 2) {
return '勘测工程师';
} else if (cellValue === 3) {
return '维修工程师';
} else {
return '工程师';
}
}
// 清空日期
const clearDate = () => {
formSearch.value.date = ''
}
// 搜索事件
const onSearchSubmit = () => {
let params = {...formSearch.value}
if(params.date !== '')
{
params.date = formatDate(params.date);
}
getApplyList(params).then((res) => {
tableData.value = res.data.records
total.value = res.data.total
})
};
const handleApprove = (item) => {
ElMessageBox.confirm('确定要通过该申请?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
approve(item.id).then((res) => {
item.status = 2;
ElMessage({
type: 'success',
message: '申请已被通过!'
})
})
}).catch(() => {
});
}
const handleReject = (item) => {
ElMessageBox.confirm('确定要拒绝该申请?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
reject(item.id).then((res) => {
item.status = 1;
ElMessage({
type: 'success',
message: '申请已被拒绝!'
})
})
}).catch(() => {
});
}
// 驳回原因
const openModel = (index) => {
ElMessageBox.prompt('请输入驳回原因', '', {
confirmButtonText: '确认',
cancelButtonText: '取消',
inputType: 'textarea',
})
.then(({ value }) => {
// 用户确认后,调用 rejectApplication 函数
if (value) { // 确保用户输入了驳回原因
reject(applicationId, value);
} else {
ElMessage({
type: 'warning',
message: '请输入驳回原因',
});
}
})
.catch(() => {
// 用户取消操作,无需处理
});
};
const handleCurrentChange = (val) => {
queryData.value.size = 10;
queryData.value.page = val;
initData(queryData.value);
};
onMounted(() => {
initData();
});
</script>
<style lang="scss" scoped>
.mt-4 {
float: right;
text-align: right;
margin-bottom: 20px;
}
.input-with-select {
max-width: 300px;
}
.expand-title {
padding: 10px;
color: #919399;
font-weight: 600;
}
</style>
+142
View File
@@ -0,0 +1,142 @@
<template>
<el-card>
<!-- <Row> 更多查看:<a href="https://vueflow.dev/">Vue Flow官方文档</a> </Row> -->
<div class="mt-4">
<el-button type="primary" @click="resetTransform">重置</el-button>
<el-button type="success" @click="updatePos">修改属性</el-button>
<el-button type="success" @click="toggleclass">修改样式</el-button>
<el-button type="warning" @click="logToObject">查看属性</el-button>
</div>
<VueFlow v-model="elements" class="vue-flow-content">
<Background />
<MiniMap />
<Controls />
</VueFlow>
</el-card>
<el-dialog
v-model="dialogVisible"
title="流程图属性"
width="70%"
:before-close="handleClose"
>
<span>{{ dialogContent }}</span>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="dialogVisible = false"
>确认</el-button
>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { ElMessage, ElMessageBox } from 'element-plus'
import '@braks/vue-flow/dist/style.css'
import '@braks/vue-flow/dist/theme-default.css'
import {
Background,
Controls,
MiniMap,
VueFlow,
isNode,
useVueFlow,
} from '@braks/vue-flow'
import { ref } from 'vue'
// import { Message } from 'view-ui-plus'
const dialogVisible = ref(false)
const dialogContent = ref('')
const elementsDefault = [
{
id: '1',
type: 'input',
label: '自律',
position: { x: 250, y: 5 },
class: 'node-light',
},
{
id: '2',
label: '控玩玩手机的时间',
position: { x: 100, y: 100 },
class: 'node-light',
},
{
id: '3',
label: '养成良好生活习惯',
position: { x: 400, y: 100 },
class: 'node-light',
},
{
id: '4',
label: '培养阅读习惯',
position: { x: 400, y: 200 },
class: 'node-light',
},
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e1-3', source: '1', target: '3' },
]
const elements = ref(elementsDefault)
const {
onPaneReady,
onNodeDragStop,
onConnect,
addEdges,
setTransform,
toObject,
} = useVueFlow({
defaultZoom: 1.5,
minZoom: 0.2,
maxZoom: 4,
})
onPaneReady(({ fitView }) => {
fitView()
})
onNodeDragStop((e) => console.log('drag stop', e))
onConnect((params) => addEdges([params]))
const updatePos = () => {
elements.value.forEach((el) => {
if (isNode(el)) {
el.position = {
x: Math.random() * 400,
y: Math.random() * 400,
}
}
})
}
const logToObject = () => {
dialogVisible.value = true
dialogContent.value = JSON.stringify(toObject())
// Message.info(JSON.stringify(toObject()))
}
const resetTransform = () => {
elements.value = elementsDefault
setTransform({ x: 0, y: 0, zoom: 1 })
}
const toggleclass = () =>
elements.value.forEach(
(el) => (el.class = el.class === 'node-light' ? 'node-dark' : 'node-light')
)
</script>
<style lang="scss" scoped>
.vue-flow-content {
height: 80vh;
.node-light {
background: none;
}
.node-dark {
background: #eeeeee;
}
}
.mt-4 {
float: right;
text-align: right;
margin-bottom: 20px;
}
</style>
+67
View File
@@ -0,0 +1,67 @@
<template>
<el-card>
<div class="card-title">添加input 🍯🍯🍯🍯🍯🍯</div>
<el-input v-model="input1" placeholder="请输入域名">
<template #prepend>Http://</template>
</el-input>
<el-input v-model="input1" placeholder="请输入..." class="mt10">
<template #prepend>
<el-select v-model="select" placeholder="" style="width: 115px">
<el-option label="邮箱" value="1" />
<el-option label="wexin" value="2" />
<el-option label="Tel" value="3" />
</el-select>
</template>
</el-input>
<el-input v-model="input1" placeholder="请输入..." class="mt10">
<template #append>.com</template>
</el-input>
<el-input v-model="input1" placeholder="请输入..." class="mt10">
<template #prepend>
<el-select v-model="select" placeholder="Select2" style="width: 115px">
<el-option label="分类一" value="1" />
<el-option label="分类二" value="2" />
<el-option label="分类三" value="3" /> </el-select
></template>
<template #append><el-button :icon="Search" /></template>
</el-input>
<el-input
class="mt10"
v-for="item in inputList"
:key="item"
:v-model="item"
placeholder="请输入"
>
<template #append
><el-button @click="deleteHanle(item)">Delete</el-button></template
>
</el-input>
<el-button icon="Plus" class="mt10 w100" @click="addInput()"
>添加</el-button
>
</el-card>
</template>
<script setup>
import { Search, Plus } from '@element-plus/icons-vue'
import { ref } from 'vue'
const input1 = ref('')
const inputList = ref([])
const select = ref('1')
const Select2 = ref('1')
const addInput = () => {
inputList.value.push('')
}
const deleteHanle = (item) => {
inputList.value.splice(inputList.value[item], 1)
}
</script>
<style lang="scss" scoped>
.card-title {
padding-bottom: 20px;
font-size: 18px;
text-align: center;
}
</style>
+79
View File
@@ -0,0 +1,79 @@
<template>
<el-card class="col-center">
<el-form :model="form" label-width="120px">
<el-form-item label="活动名称">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="form.region" placeholder="please select your zone">
<el-option label="区域一" value="shanghai" />
<el-option label="区域二" value="beijing" />
</el-select>
</el-form-item>
<el-form-item label="活动日期">
<el-col :span="11">
<el-date-picker
v-model="form.date1"
type="date"
placeholder="开始日期"
style="width: 100%"
/>
</el-col>
<el-col :span="2" class="开启活动">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-time-picker
v-model="form.date2"
placeholder="结束日期"
style="width: 100%"
/>
</el-col>
</el-form-item>
<el-form-item label="活动状态">
<el-switch v-model="form.delivery" />
</el-form-item>
<el-form-item label="活动类型">
<el-checkbox-group v-model="form.type">
<el-checkbox label="Online activities" name="type" />
<el-checkbox label="Promotion activities" name="type" />
<el-checkbox label="Offline activities" name="type" />
<el-checkbox label="Simple brand exposure" name="type" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="活动资源">
<el-radio-group v-model="form.resource">
<el-radio label="Sponsor" />
<el-radio label="Venue" />
</el-radio-group>
</el-form-item>
<el-form-item label="活动描述">
<el-input v-model="form.desc" type="textarea" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
// do not use same name with ref
const form = reactive({
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
})
const onSubmit = () => {
console.log('submit!')
}
</script>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+109
View File
@@ -0,0 +1,109 @@
<template>
<el-card class="box-card" shadow="never"> 卡片列表 🍓🍇🍈🍉 </el-card>
<el-row
class="mt10"
style="height: 75vh; overflow: auto"
v-infinite-scroll="load"
>
<el-col :span="6" v-for="item in listData" :key="item" offset="1">
<el-card shadow="hover" class="card-lists">
<!-- <div
class="item-state-pos"
:style="{
backgroundColor:
item.pay_state == '1002'
? '#6C88D5'
: item.pay_state == '1003'
? '#fa4a1e'
: '#00AA5A',
}"
>
{{
item.pay_state == '1001'
? '已支付'
: item.pay_state == '1002'
? '待支付'
: '未支付'
}}
</div> -->
<div class="item-state-pos">
<el-icon><MoreFilled /></el-icon>
</div>
<div class="item-title">
<img src="../../assets/images/avart.jpg" alt="" />{{ item.title }}
</div>
<div class="item-content flx-row">
<div class="cot">
<div class="cot-tit">发行日期</div>
<div class="cot-txt">{{ item.date }}</div>
</div>
<div class="cot">
<div class="cot-tit">客户姓名</div>
<div class="cot-txt">{{ item.user_name }}</div>
</div>
</div>
<div class="item-content flx-row">
<div class="cot">
<div class="cot-tit">
金额 <span>{{ item.number }}</span>
</div>
</div>
<div class="cot">
<div class="cot-tit">
状态
<span
:class="[
item.pay_state == '1002'
? 'type suc-type'
: item.pay_state == '1003'
? 'type'
: 'type error-type',
]"
>{{
item.pay_state == '1001'
? '已支付'
: item.pay_state == '1002'
? '待支付'
: '未支付'
}}</span
>
</div>
</div>
</div>
<div class="item-content flx-row">
<div class="cot">
<div class="cot-tit">详情</div>
<div class="cot-txt one-cut-txt">{{ item.content }}</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
</template>
<script setup>
import { cardlists } from '../../api/modules/index.js'
import { onMounted, ref } from 'vue'
const listData = ref([])
const load = () => {
cardlists().then((res) => {
listData.value = listData.value.concat(res.data.data)
})
// count.value += 2
}
const getListData = () => {
cardlists().then((res) => {
listData.value = res.data.data
})
}
onMounted(() => {
getListData()
})
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>
+80
View File
@@ -0,0 +1,80 @@
<template>
<el-card class="box-card" shadow="never"> 基础列表 🍓🍇🍈🍉 </el-card>
<div v-infinite-scroll="load" class="infinite-list" style="overflow: auto">
<div class="barlist flx-row" v-for="i in listData" :key="i">
<div class="item-img">
<img src="../../assets/images/avart.jpg" alt="" />
</div>
<div class="item-left">
<div class="name">{{ i.createUser }}</div>
<div class="subname">{{ i.email }}</div>
</div>
<div class="item-left">
<div class="name">{{ i.title }}</div>
<div class="subname">{{ i.createTime }}发票已发出</div>
</div>
<div class="item-right">{{ i.number }}</div>
<div
class="item-state flx-row"
:style="{
backgroundColor:
i.pay_state == '1002'
? '#6C88D5'
: i.pay_state == '1003'
? '#fa4a1e'
: '#00AA5A',
}"
>
<span>{{
i.pay_state == '1001'
? '已支付'
: i.pay_state == '1002'
? '待支付'
: '未支付'
}}</span>
</div>
</div>
<!-- <div v-for="i in listData" :key="i" class="infinite-list-item">
<div class="infinite-list-item-top">
{{ i.title }}
</div>
<div class="infinite-list-item-main flx-row">
<div style="flex: 1">创建人:{{ i.createUser }}</div>
<div style="flex: 1">发布时间:{{ i.createTime }}</div>
</div>
</div>-->
</div>
</template>
<script setup>
import { Newslist } from '../../api/modules/index.js'
import { onMounted, ref } from 'vue'
const listData = ref([])
const load = () => {
Newslist().then((res) => {
listData.value = listData.value.concat(res.data.data)
})
// count.value += 2
}
const getListData = () => {
Newslist().then((res) => {
listData.value = res.data.data
})
}
onMounted(() => {
getListData()
})
</script>
<style lang="scss" scoped>
.box-card {
width: 100%;
.box-card-title {
margin-bottom: 20px;
}
}
@import './index.scss';
</style>
-546
View File
@@ -1,546 +0,0 @@
<template>
<el-card class="mt10">
<el-button type="success" @click="drawer = true;drawerEdit = false">
<el-icon style="margin-right: 10px;"><CirclePlus /></el-icon>
创建服务
</el-button>
<el-drawer v-model="drawer" :direction="direction" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :show-close="false">
<template v-if="!drawerEdit" #header>
<h4>创建服务</h4>
</template>
<template v-else #header>
<h4>编辑服务</h4>
</template>
<template #default>
<el-form
:model="formData"
label-width="auto" v-loading="loading">
<el-form-item label="服务名称" prop="formData.goodsName">
<el-input
v-model="formData.goodsName"
maxlength="6"
placeholder="请输入服务名称"
></el-input>
</el-form-item>
<el-form-item label="服务价格" prop="price">
<el-input type="number" v-model="formData.price" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="状态" prop="formData.isList">
<el-switch
v-model="formData.isList"
inline-prompt
active-text="上架"
inactive-text="下架"
/>
</el-form-item>
<el-form-item label="服务图标">
<el-upload
v-model:file-list="fileIcon"
list-type="picture-card"
:before-upload="beforeUpload"
:http-request="addUploadIconFile"
:limit="1"
:on-exceed="handleIconExceed"
:on-remove="handleIconRemove"
>
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item label="轮播图">
<el-upload
v-model:file-list="fileBannerList"
multiple
list-type="picture-card"
:before-upload="beforeUpload"
:http-request="addUploadCarouselImageFile"
:limit="5"
:on-exceed="handleBannerExceed"
:on-remove="handleBannerRemove"
>
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item label="详情图">
<el-upload
v-model:file-list="fileDetail"
list-type="picture-card"
:before-upload="beforeUpload"
:http-request="addUploadDetailFile"
:limit="1"
:on-exceed="handleDetailExceed"
:on-remove="handleDetailRemove"
>
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
<div style="display: flex; justify-content: flex-end; margin-top: 50px">
<el-button @click="cancelDrawer">取消</el-button>
<el-button type="primary" @click="onSubmit">确认</el-button>
</div>
</el-form>
</template>
</el-drawer>
<el-table
ref="table"
:data="tableData"
:default-sort="{ prop: 'date', order: 'descending' }"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
class="mt20"
>
<el-table-column
v-for="item in options"
:key="item.type"
:prop="item.props"
:label="item.label"
:width="item.width"
:align="item.align"
>
<template v-slot:default="scope" v-if="item.props === 'price'">
{{ formatPrice(scope.row.price) }}
</template>
<template v-slot:default="scope" v-if="item.props === 'isList'">
<el-switch
v-model="scope.row.isList"
inline-prompt
active-text="上架"
inactive-text="下架"
@change="upStatus(scope.row)"
/>
</template>
<template v-slot:default="scope" v-if="item.props === 'icon'">
<el-image
style="width: 300px; height: 200px"
:src="scope.row.icon"
/>
</template>
<template v-slot:default="scope" v-if="item.props === 'carouselImage'">
<view v-for="itemImg in scope.row.carouselImage">
<el-image
:src="itemImg.url"
style="width:150px; height: 80px;margin-right: 5px;"
:style="{
boxShadow: `var(light)`,
}"
/>
</view>
</template>
<template v-slot:default="scope" v-if="item.props === 'details'">
<el-image
style="width: 300px; height: 200px"
:src="scope.row.details"
/>
</template>
<template v-slot:default="scope" v-if="item.props === 'actions'">
<!-- <el-button-->
<!-- type="info"-->
<!-- size="small"-->
<!-- @click="viewItem(scope.row)"-->
<!-- >查看</el-button>-->
<!-- <el-button-->
<!-- type="info"-->
<!-- size="small"-->
<!-- @click="editItem(scope.row)"-->
<!-- >编辑</el-button>-->
<el-popconfirm
confirm-button-text="确认"
cancel-button-text="取消"
:icon="InfoFilled"
icon-color="#626AEF"
title="确定要删除该服务项目?"
@confirm="deleteItem(scope.row)"
>
<template #reference>
<el-button type="danger" size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
size="small"
background
layout="prev, pager, next"
:total="tableData.length"
class="mt-4 mt10"
@current-change="handleCurrentChange"
/>
</el-card>
</template>
<script setup>
import {
CirclePlus,
Plus,
InfoFilled,
View,
Edit,
Delete,
} from '@element-plus/icons-vue'
import {getGoodsList, addGoods, updateGoods, delGoods} from '../../api/modules/goods.js'
import { addFile } from '../../api/modules/upload'
import { options } from './options.js'
import { onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
const queryData = ref({
keyWord: '',
page: 1,
size: 10,
})
const tableData = ref([])
const total = ref(0)
const drawer = ref(false)
const drawerEdit = ref(false)
const direction = ref('rtl')
const loading = ref(false)
const formData = ref({
goodsName: '',
price: '',
carouselImage: [],
details: '',
icon: '',
isList: false
})
const fileBannerList = ref([]); // 轮播图
const fileDetail = ref([]); // 详情图
const fileIcon = ref([]); // 服务图标
// 页面初始化
const initData = () => {
getGoodsList(queryData.value).then((res) => {
tableData.value = res.data.map(item => {
try {
// 尝试将字符串转换为 JSON 对象
item.carouselImage = JSON.parse(item.carouselImage);
} catch (error) {
// 设置一个默认值或者保留原来的字符串
item.carouselImage = {}; // 或者保留原来的字符串
}
return item;
});
total.value = res.total
})
}
// 上传前的钩子
const beforeUpload = (file) => {
loading.value = true;
const maxSize = 5 * 1024 * 1024; // 最大 2MB
if (file.size > maxSize) {
alert('文件大小不能超过 5MB');
loading.value = false;
return false;
}
const allowedTypes = ['image/jpeg', 'image/png'];
if (!allowedTypes.includes(file.type)) {
alert('只允许上传 JPEG 或 PNG 图片');
loading.value = false;
return false;
}
console.log('文件准备上传:', file);
return true;
}
// 轮播图片上传限制
const handleBannerExceed= (files, uploadFiles) => {
ElMessage.warning(
`轮播图最多可上传5张`
)
}
// 详情图片上传限制
const handleDetailExceed= (files, uploadFiles) => {
ElMessage.warning(
`详情图最多可上传1张`
)
}
// 服务图标上传限制
const handleIconExceed = (files, uploadFiles) => {
ElMessage.warning(
`服务图标最多可上传1张`
)
}
// 轮播图移除
const handleBannerRemove = (file) => {
let fileName = file.name; // 移除的文件名
// 更新 formData 中的 details
formData.value.carouselImage = formData.value.carouselImage.filter(item => item.name !== file.name);
}
// 详情图移除
const handleDetailRemove = (file, fileList) => {
formData.value.details = '';
}
// 服务图表移除
const handleIconRemove = (file, fileList) => {
formData.value.icon = '';
}
// 轮播上传请求
const addUploadCarouselImageFile = (params) => {
const formData = new FormData();
formData.append('files', params.file);
addFile(formData)
.then((response) => {
handleCarouselImageSuccess(response, params.file, params.fileList);
})
.catch((error) => {
if(error)
{
handleError(error, params.file, params.fileList);
}
});
}
// 详情上传
const addUploadDetailFile = (params) => {
const formData = new FormData();
formData.append('files', params.file);
addFile(formData)
.then((response) => {
handleDetailSuccess(response, params.file, params.fileList);
})
.catch((error) => {
if(error)
{
handleError(error, params.file, params.fileList);
}
});
}
// 服务图标上传
const addUploadIconFile = (params) => {
const formData = new FormData();
formData.append('files', params.file);
addFile(formData)
.then((response) => {
handleIconSuccess(response, params.file, params.fileList);
})
.catch((error) => {
if(error)
{
handleError(error, params.file, params.fileList);
}
});
}
// 处理轮播上传成功的回调
const handleCarouselImageSuccess = (response, file) => {
let fileObj = {
'name': file.name,
'url': response.data[0]
};
formData.value.carouselImage.push(fileObj);
loading.value = false;
}
// 处理详情上传成功的回调
const handleDetailSuccess = (response) => {
formData.value.details = response.data[0];
loading.value = false;
}
// 处理服务图标上传成功的回调
const handleIconSuccess = (response) => {
formData.value.icon = response.data[0];
loading.value = false;
}
// 处理上传失败的回调
const handleError = (error, file, fileList) => {
loading.value = false;
console.error('上传失败:', error, file, fileList);
}
// 上下架处理
const upStatus = (env) => {
let formData = {
id: env.id,
isList: env.isList
};
updateGoods(formData).then((res) => {
if(formData.isList)
{
ElMessage({
message: '上架成功',
type: 'success',
});
}else{
let msg = '';
ElMessage({
message: '下架成功',
type: 'success',
});
}
initData();
});
}
// 格式化价格
const formatPrice = (price) => {
return parseFloat(price).toFixed(2);
}
// 提交表单
const onSubmit = () => {
if (!formData.value.goodsName || !formData.value.price || !formData.value.details || formData.value.carouselImage.length < 1 ) {
ElMessage.error('请填写完整信息');
return;
}
let params = {...formData.value}
params.carouselImage = JSON.stringify(params.carouselImage); // 转为字符串
addGoods(params)
.then((res) => {
drawer.value = false;
formData.value = {
goodsName: '',
price: '',
carouselImage: [],
details: '',
isList: false
}
fileBannerList.value = [];
fileDetail.value = [];
ElMessage({
message: '添加成功',
type: 'success',
})
initData();
})
.catch((err) => {
console.error('添加失败:', err);
})
// if (drawer.value) {
//
// } else {
// updateGoods(formData.value)
// .then((res) => {
// ElMessage({
// message: '编辑服务项目成功',
// type: 'success',
// })
// tableData.value = tableData.value.map(item => item.id === formData.value.id ? formData.value : item)
// drawer.value = false
// })
// .catch((err) => {
// console.error('更新失败:', err);
// })
// }
}
// 点击取消
const cancelDrawer = () => {
drawer.value = false;
drawerEdit.value = false;
loading.value = false;
formData.value = {
goodsName: '',
price: '',
carouselImage: [],
details: '',
isList: false
}
fileBannerList.value = [];
fileDetail.value = [];
}
// 分页切换
const handleCurrentChange = (val) => {
queryData.value.page = val
initData()
}
// 编辑项
const editItem = (item) => {
formData.value = { ...item }
drawer.value = true;
drawerEdit.value = true;
}
// 查看项
const viewItem = (item) => {
console.log('查看项:', item)
}
// 删除项
const deleteItem = (env) => {
let ItemId = env.id; // 项目ID
// 删除
delGoods(ItemId).then((res) =>{
ElMessage({
message: '删除成功',
type: 'success',
});
initData(); // 重新加载数据
});
}
// 进入页面加载
onMounted(() => {
initData()
})
</script>
<style lang="scss" scoped>
</style>
-45
View File
@@ -1,45 +0,0 @@
export const options = [
{
label: '服务名称',
props: 'goodsName',
width: '200',
align: 'left'
},
{
label: '服务价格',
props: 'price',
width: '150',
align: 'left'
}, {
label: '状态',
props: 'isList',
width: '150',
align: 'left'
},
{
label: '服务图标',
props: 'icon',
width: 'auto',
align: 'left'
},
{
label: '轮播图',
props: 'carouselImage',
width: '500',
align: 'left'
},
{
label: '服务详情',
props: 'details',
width: 'auto',
align: 'left',
},
{
label: '操作',
props: 'actions',
width: '300',
align: 'center',
fixed: 'right',
}
]
+259
View File
@@ -0,0 +1,259 @@
<template>
<el-card class="box-card" shadow="never">
<div class="flx-row">
搜索列表 🍓🍇🍈🍉
<el-input
type="text"
placeholder="请输入关键字..."
style="width: 300px; margin-left: 10px"
v-model="searchValue"
>
<template #append>
<el-button type="primary" :icon="Search" />
</template>
</el-input>
<div style="flex: 1"></div>
<div class="img" @click="checkList('1001')">
<svg
t="1663432921802"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="4971"
data-spm-anchor-id="a313x.7781069.0.i30"
width="20"
height="20"
:fill="colorType == '1001' ? '#1250FC' : '#888888'"
>
<path
d="M849.1 128 174.9 128c-25.9 0-46.9 21-46.9 46.9l0 34.2c0 25.9 21 46.9 46.9 46.9l674.2 0c25.9 0 46.9-21 46.9-46.9l0-34.2C896 149 875 128 849.1 128z"
p-id="4972"
></path>
<path
d="M849.1 768 174.9 768c-25.9 0-46.9 21-46.9 46.9l0 34.2c0 25.9 21 46.9 46.9 46.9l674.2 0c25.9 0 46.9-21 46.9-46.9l0-34.2C896 789 875 768 849.1 768z"
p-id="4973"
></path>
<path
d="M849.1 448 174.9 448c-25.9 0-46.9 21-46.9 46.9l0 34.2c0 25.9 21 46.9 46.9 46.9l674.2 0c25.9 0 46.9-21 46.9-46.9l0-34.2C896 469 875 448 849.1 448z"
p-id="4974"
></path>
</svg>
</div>
<div class="img" @click="checkList('1002')">
<svg
t="1663433235072"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="5148"
width="23"
height="23"
:fill="colorType == '1002' ? '#1250FC' : '#888888'"
>
<path
d="M433.1 480 174.9 480c-25.9 0-46.9-21-46.9-46.9L128 174.9c0-25.9 21-46.9 46.9-46.9l258.2 0c25.9 0 46.9 21 46.9 46.9l0 258.2C480 459 459 480 433.1 480z"
p-id="5149"
></path>
<path
d="M433.1 896 174.9 896c-25.9 0-46.9-21-46.9-46.9L128 590.9c0-25.9 21-46.9 46.9-46.9l258.2 0c25.9 0 46.9 21 46.9 46.9l0 258.2C480 875 459 896 433.1 896z"
p-id="5150"
></path>
<path
d="M849.1 480 590.9 480c-25.9 0-46.9-21-46.9-46.9L544 174.9c0-25.9 21-46.9 46.9-46.9l258.2 0c25.9 0 46.9 21 46.9 46.9l0 258.2C896 459 875 480 849.1 480z"
p-id="5151"
></path>
<path
d="M849.1 896 590.9 896c-25.9 0-46.9-21-46.9-46.9L544 590.9c0-25.9 21-46.9 46.9-46.9l258.2 0c25.9 0 46.9 21 46.9 46.9l0 258.2C896 875 875 896 849.1 896z"
p-id="5152"
></path>
</svg>
</div>
</div>
</el-card>
<div
v-infinite-scroll="load"
class="infinite-list"
style="overflow: auto"
v-if="colorType == 1001"
>
<div class="barlist flx-row" v-for="i in listData" :key="i">
<div class="item-img">
<img src="../../assets/images/avart.jpg" alt="" />
</div>
<div class="item-left">
<div class="name">{{ i.createUser }}</div>
<div class="subname">{{ i.email }}</div>
</div>
<div class="item-left">
<div class="name">{{ i.title }}</div>
<div class="subname">{{ i.createTime }}发票已发出</div>
</div>
<div class="item-right">{{ i.number }}</div>
<div
class="item-state flx-row"
:style="{
backgroundColor:
i.pay_state == '1002'
? '#6C88D5'
: i.pay_state == '1003'
? '#fa4a1e'
: '#00AA5A',
}"
>
<span>{{
i.pay_state == '1001'
? '已支付'
: i.pay_state == '1002'
? '待支付'
: '未支付'
}}</span>
</div>
</div>
</div>
<el-row
class="mt10"
style="height: 75vh; overflow: auto"
v-infinite-scroll="load"
v-if="colorType == 1002"
>
<el-col :span="6" v-for="item in cardlist" :key="item" offset="1">
<el-card shadow="hover" class="card-lists">
<!-- <div
class="item-state-pos"
:style="{
backgroundColor:
item.pay_state == '1002'
? '#6C88D5'
: item.pay_state == '1003'
? '#fa4a1e'
: '#00AA5A',
}"
>
{{
item.pay_state == '1001'
? '已支付'
: item.pay_state == '1002'
? '待支付'
: '未支付'
}}
</div> -->
<div class="item-state-pos">
<el-icon><MoreFilled /></el-icon>
</div>
<div class="item-title">
<img src="../../assets/images/avart.jpg" alt="" />{{ item.title }}
</div>
<div class="item-content flx-row">
<div class="cot">
<div class="cot-tit">发行日期</div>
<div class="cot-txt">{{ item.date }}</div>
</div>
<div class="cot">
<div class="cot-tit">客户姓名</div>
<div class="cot-txt">{{ item.user_name }}</div>
</div>
</div>
<div class="item-content flx-row">
<div class="cot">
<div class="cot-tit">
金额 <span>{{ item.number }}</span>
</div>
</div>
<div class="cot">
<div class="cot-tit">
状态
<span
:class="[
item.pay_state == '1002'
? 'type suc-type'
: item.pay_state == '1003'
? 'type'
: 'type error-type',
]"
>{{
item.pay_state == '1001'
? '已支付'
: item.pay_state == '1002'
? '待支付'
: '未支付'
}}</span
>
</div>
</div>
</div>
<div class="item-content flx-row">
<div class="cot">
<div class="cot-tit">详情</div>
<div class="cot-txt one-cut-txt">{{ item.content }}</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
</template>
<script setup>
import { ElMessage } from 'element-plus'
import { Newslist, cardlists } from '../../api/modules/index.js'
import { Search, Plus } from '@element-plus/icons-vue'
import { onMounted, ref } from 'vue'
const listData = ref([])
const cardlist = ref([])
const searchValue = ref('')
const colorType = ref('1001')
const load = () => {
if (colorType == '1002') {
cardlists().then((res) => {
cardlist.value = res.data.data
})
} else {
Newslist().then((res) => {
listData.value = listData.value.concat(res.data.data)
})
}
// count.value += 2
}
const getListData = () => {
Newslist().then((res) => {
listData.value = res.data.data
})
cardlists().then((res) => {
cardlist.value = res.data.data
})
}
const checkList = (type) => {
colorType.value = type
if (type == 1001) {
ElMessage({
message: '单列展示,切换成功!',
type: 'success',
})
} else {
ElMessage({
message: '多列展示,切换成功!',
type: 'success',
})
}
}
onMounted(() => {
getListData()
})
</script>
<style lang="scss" scoped>
.box-card {
width: 100%;
.box-card-title {
margin-bottom: 20px;
}
}
@import './index.scss';
</style>
+172
View File
@@ -0,0 +1,172 @@
<template>
<div id="main" style="width: 100%; height: 100%"></div>
</template>
<script setup name="GMVnearly">
import * as echarts from 'echarts'
import { onMounted } from 'vue'
const getEcharts = () => {
var chartDom = document.getElementById('main')
var myChart = echarts.init(chartDom)
const option = {
tooltip: {
//鼠标悬停时显示对应数据
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
},
title: {
text: '出入库情况',
top: '8px',
left: '10px',
bottom: '8px',
textStyle: {
color: '#191e24',
fontSize: '14',
},
},
legend: {
// 图例
data: ['出库', '入库'],
top: 8,
right: 16, // 修改位置
icon: 'circle', //原型
textStyle: {
color: '#191e2480', //字体颜色
},
},
grid: {
// 上下左右 边距
top: '8%',
left: '3%',
right: '3%',
bottom: '8%',
top: '15%',
containLabel: true,
},
xAxis: [
{
type: 'category',
axisTick: { show: false },
data: [
'1月',
'2月',
'3月',
'4月',
'5月',
'6月',
'7月',
'8月',
'9月',
'10月',
'11月',
'12月',
],
axisLine: {
// 轴线的颜色以及宽度
lineStyle: {
color: '#A6A6A628',
},
},
axisLabel: {
// 轴文字的配置
show: true,
textStyle: {
color: '#191e2480',
},
},
splitLine: {
// 分割线配置
lineStyle: {
color: '#A6A6A628',
// type: "dashed", // 虚线
},
},
},
],
yAxis: [
{
min: 0, // 最小值
max: 500, //最大值
// splitNumber: 3, //划分3格
type: 'value',
axisLine: {
// 轴线的颜色以及宽度
show: false,
},
axisLabel: {
// 轴文字的配置
show: true,
// textStyle: {
// color: "#fff",
// },
},
splitLine: {
// 分割线配置
lineStyle: {
color: '#A6A6A628',
// type: "dashed",
},
},
},
],
series: [
{
name: '出库',
type: 'bar',
barWidth: 10, // 柱图宽度
barGap: '30%',
// label: labelOption,
emphasis: {
focus: 'series',
},
data: [320, 332, 401, 334, 390, 320, 332, 301, 334, 390, 320, 332],
// ↓ 这里可以改变渐变色的方向
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 0,
color: '#6E48E6',
},
{
offset: 1,
color: '#3AA6FA ',
},
]),
},
{
name: '入库',
type: 'bar',
barWidth: 10, // 柱图宽度
// label: labelOption,
emphasis: {
focus: 'series',
},
data: [220, 182, 191, 234, 290, 220, 182, 191, 234, 290, 220, 182],
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 0,
color: '#9DDD92',
},
{
offset: 1,
color: '#10BFAA',
},
]),
},
],
}
option && myChart.setOption(option)
window.onresize = () => {
myChart.resize()
}
}
onMounted(() => {
setTimeout(() => {
getEcharts()
}, 1000)
})
</script>
+149
View File
@@ -0,0 +1,149 @@
<template>
<div id="linenearly" style="width: 100%; height: 100%"></div>
</template>
<script setup name="GMVnearly">
import * as echarts from 'echarts'
import { onMounted } from 'vue'
const getEcharts = () => {
var chartDom = document.getElementById('linenearly')
var myChart = echarts.init(chartDom)
const option = {
tooltip: {
//鼠标悬停时显示对应数据
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
},
color: ['#87A2E8FF', '#74CCCCFF'],
title: {
text: '近一年的DAU/DNU',
top: '8px',
left: '10px',
bottom: '8px',
textStyle: {
color: '#191e24',
fontSize: '14',
},
},
legend: {
// 图例
data: ['DAU', 'DNU'],
top: 8,
right: 16, // 修改位置
icon: 'circle', //原型
textStyle: {
color: '#191e2480', //字体颜色
},
},
grid: {
// 上下左右 边距
top: '8%',
left: '3%',
right: '3%',
bottom: '8%',
top: '15%',
containLabel: true,
},
xAxis: [
{
type: 'category',
axisTick: { show: false },
data: [
'1月',
'2月',
'3月',
'4月',
'5月',
'6月',
'7月',
'8月',
'9月',
'10月',
'11月',
'12月',
],
axisLine: {
// 轴线的颜色以及宽度
lineStyle: {
color: '#A6A6A628',
},
},
axisLabel: {
// 轴文字的配置
show: true,
textStyle: {
color: '#191e2480',
},
},
splitLine: {
// 分割线配置
lineStyle: {
color: '#A6A6A628',
// type: "dashed", // 虚线
},
},
},
],
yAxis: [
{
min: 0, // 最小值
// splitNumber: 3, //划分3格
type: 'value',
axisLine: {
// 轴线的颜色以及宽度
show: false,
},
axisLabel: {
// 轴文字的配置
show: true,
// textStyle: {
// color: "#fff",
// },
},
splitLine: {
// 分割线配置
lineStyle: {
color: '#A6A6A628',
// type: "dashed",
},
},
},
],
series: [
{
name: 'DAU',
type: 'line',
stack: 'Total',
areaStyle: {},
emphasis: {
focus: 'series',
},
data: [120, 132, 101, 134, 90, 230, 210, 134, 90, 230, 210, 230],
},
{
name: 'DNU',
type: 'line',
stack: 'Total',
areaStyle: {},
emphasis: {
focus: 'series',
},
data: [120, 132, 101, 134, 90, 230, 210, 134, 90, 230, 210, 290],
},
],
}
option && myChart.setOption(option)
window.onresize = () => {
myChart.resize()
}
}
onMounted(() => {
setTimeout(() => {
getEcharts()
}, 1000)
})
</script>
+303
View File
@@ -0,0 +1,303 @@
<template>
<el-row class="data-lists">
<el-col :span="9" :class="{ shake: disabled }"
><div class="data-item-one flx-row">
<div class="item-left">
<img src="../../assets/home.png" alt="" srcset="" />
</div>
<div class="item-right">
<div class="item-right-top">
<div class="tit">本期活动GMX</div>
<div class="num">1523.53w</div>
</div>
<div class="line"></div>
<div class="item-right-bottom flx-row">
<div class="item">
<div class="tit">类目一</div>
<div class="num">53w</div>
</div>
<div class="item">
<div class="tit">类目一</div>
<div class="num">53w</div>
</div>
<div class="item">
<div class="tit">类目一</div>
<div class="num">53w</div>
</div>
</div>
</div>
</div></el-col
>
<el-col :span="9" :class="{ shake: disabled }"
><div class="data-item-two">
<div class="item">
<div class="item-des flx-row">
<img src="../../assets/icon1.png" alt="" />
<div class="right">
<div class="num">934.7w <span>29.74</span></div>
<div class="txt">今日DAU</div>
</div>
</div>
</div>
<div class="item">
<div class="item-des flx-row" style="margin-right: 0px">
<img src="../../assets/icon2.png" alt="" />
<div class="right">
<div class="num">264.7w <span>29.74</span></div>
<div class="txt">今日DAU</div>
</div>
</div>
</div>
<div class="item">
<div class="item-des flx-row">
<div class="right border-right-1px">
<div class="num">24.93w</div>
<div class="txt">今日DAU</div>
</div>
<div class="right">
<div class="num">984.52w</div>
<div class="txt">总用户数</div>
</div>
</div>
</div>
<div class="item">
<div class="item-des flx-row" style="margin-right: 0px">
<div class="right border-right-1px">
<div class="num">84.52w</div>
<div class="txt">GPS</div>
</div>
<div class="right">
<div class="num">84.52w</div>
<div class="txt">特权</div>
</div>
</div>
</div>
</div></el-col
>
<el-col :span="6" :class="{ shakeRight: disabled }">
<div class="data-item-three">
<div class="tit">待处理</div>
<div class="content">
<div class="item">
<div class="item-data">
<div class="tit">退款申请</div>
<div class="num">89 <span>条</span></div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
<div class="item">
<div class="item-data">
<div class="tit">退款申请</div>
<div class="num">89 <span>条</span></div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
<div class="item">
<div class="item-data">
<div class="tit">退款申请</div>
<div class="num">89 <span>条</span></div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
<div class="item">
<div class="item-data">
<div class="tit">退款申请</div>
<div class="num">89 <span>条</span></div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
</div>
</div>
</el-col>
</el-row>
<el-row class="dataLayer">
<el-col :span="18">
<div class="flx-row">
<div class="datalayer-echarts" :class="{ shake: disabled }">
<GMVnearly></GMVnearly>
</div>
<div class="datalayer-echarts" :class="{ shake: disabled }">
<linenearly></linenearly>
</div>
</div>
<div class="table-data" :class="{ shake: disabled }">
<div class="tit">主题页列表</div>
<div class="table-box">
<el-table
:data="tableData"
:header-cell-style="{
background: '#FAFBFDFF',
fontWeight: '400',
fontSize: '14px',
padding: '0',
fontHeight: '36px',
height: '36px',
}"
:row-style="{
fontWeight: '400',
fontSize: '14px',
padding: '0',
fontHeight: '44px',
height: '44px',
}"
>
<el-table-column
v-for="item in options"
:key="item.type"
:prop="item.props"
:label="item.label"
:width="item.width"
:align="item.align"
show-overflow-tooltip
:fixed="item.fixed"
>
<template v-slot:default="scope" v-if="item.props === 'type'">
<span class="type" v-if="scope.row[item.props] == true"
>外部链接</span
>
<span
class="type error-type"
v-if="scope.row[item.props] == false"
>内部链接</span
>
</template>
<template v-slot:default="scope" v-if="item.props === 'state'">
<span v-if="scope.row[item.props] == true">
<i class="state"></i>已上线</span
>
<span v-if="scope.row[item.props] == false">
<i class="state error-state"></i>已下线</span
>
</template>
<template v-slot:default="scope" v-if="item.props === 'actions'">
<el-icon class="icon-edit" @click="editorClick(scope.row)"
><Edit
/></el-icon>
<el-popconfirm
confirm-button-text="确认"
cancel-button-text="取消"
:icon="InfoFilled"
icon-color="#626AEF"
title="确认删除该主题?"
@confirm="DeleteItem(index)"
>
<template #reference>
<el-icon class="icon-dele"><Delete /></el-icon>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-col>
<el-col :span="6">
<div class="data-item-three" :class="{ shakeRight: disabled }">
<div class="tit">常用功能</div>
<div class="content">
<div class="item">
<div class="item-data flx-row">
<div class="tit">
<el-icon><Histogram /></el-icon>订单列表
</div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
<div class="item">
<div class="item-data flx-row">
<div class="tit">
<el-icon><Avatar /></el-icon>用户列表
</div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
<div class="item">
<div class="item-data">
<div class="tit">
<el-icon><HomeFilled /></el-icon>首页配置
</div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
<div class="item">
<div class="item-data">
<div class="tit">
<el-icon><PictureFilled /></el-icon>主题配置
</div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
<div class="item">
<div class="item-data">
<div class="tit">
<el-icon><Menu /></el-icon>活动管理
</div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
<div class="item">
<div class="item-data">
<div class="tit">
<el-icon><Tools /></el-icon>退款申请
</div>
<el-icon class="icon"><ArrowRight /></el-icon>
</div>
</div>
</div>
</div>
<div class="notice">
<div class="notice-news">
<img src="../../assets/homebg.jpeg" alt="" />
<div class="txt one-cut-txt">
查看更多查看更多查看更多查看更查看更多查看更多查看更多查看更
</div>
</div>
</div>
<div class="data-item-three" :class="{ shakeRight: disabled }">
<div class="tit">公告栏</div>
<div class="notice-lists">
<div class="item one-cut-txt" v-for="item in notList" :key="item.id">
<span class="type">通知</span> {{ item.text }}
</div>
</div>
</div>
</el-col>
</el-row>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import GMVnearly from './components/GMVnearly.vue'
import linenearly from './components/linenearly.vue'
import { options } from './options.js'
import { homeList, noticeLists } from '../../api/modules/index.js'
const tableData = ref([])
const notList = ref([])
const disabled = ref(false)
const DeleteItem = (index) => {
tableData.value.splice(index, 1)
}
const initData = () => {
homeList().then((res) => {
tableData.value = res.data.data
})
noticeLists().then((res) => {
notList.value = res.data.data
})
}
onMounted(() => {
initData()
disabled.value = true
setTimeout(() => {
disabled.value = false
}, 1500)
})
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>
+1 -3
View File
@@ -1,8 +1,6 @@
<template>
<el-card>
<div>
欢迎回来,重庆创兴佳后台管理后台!
</div>
<div>欢迎使用💐🌸💮🏵️🌹🌺🌻</div>
</el-card>
</template>
+6 -10
View File
@@ -2,8 +2,8 @@
<div class="login-container flx-center">
<div class="login-box">
<div class="login-left">
<div class="title">创兴佳科技</div>
<div class="sub">控制面板</div>
<div class="title">隐患上报风险防控</div>
<div class="sub">后台数据管理</div>
<img src="../../assets/login.png" alt="" />
</div>
@@ -57,7 +57,9 @@
size="large"
type="primary"
:loading="loading"
>登录</el-button>
>
登录
</el-button>
</div>
<!-- <el-divider>其他方式登录 </el-divider>
<div class="flx-row">
@@ -135,11 +137,6 @@
</div> -->
</div>
</div>
<!-- 备案号放在 login-box 外面,居中显示 -->
<div class="beian-info" style="position: absolute; bottom: 20px; width: 100%; text-align: center; color: #999; font-size: 16px;">
渝ICP备2024040579号
</div>
</div>
</template>
@@ -170,8 +167,7 @@ const login = (formEl) => {
if (!formEl) return;
formEl.validate((valid) => {
if (valid) {
// 不知道提交失败后怎么关闭,暂时先不开启
// loading.value = true;
loading.value = true;
console.log(globalStore);
if (loginForm.checked) {
+29
View File
@@ -0,0 +1,29 @@
.el-row {
margin-bottom: 20px;
}
.el-row:last-child {
margin-bottom: 0;
}
.el-col {
border-radius: 4px;
background-color: #fff;
/* margin-right: 20px; */
height: 100%;
}
.material-header {
padding: 10px;
color: #666;
border-bottom: 2px solid #f0f2f5;
.tit {
flex: 1;
}
}
.material-content {
padding: 10px;
}
+29
View File
@@ -0,0 +1,29 @@
<template>
<el-row style="height: 90vh">
<el-col :span="6" style="border-right: 10px solid #f0f2f5">
<div class="material-header flx-row">
<div class="tit">目录</div>
<div>
<el-icon><MoreFilled /></el-icon>
</div>
</div>
</el-col>
<el-col :span="18">
<div class="material-header flx-row">
<div class="tit">我的文件</div>
<div>
<el-icon><MoreFilled /></el-icon>
</div>
</div>
<div class="material-content">
<div class="flx-row">
<div class="item"></div>
</div>
</div>
</el-col>
</el-row>
</template>
<style lang="scss" scoped>
@import './index.scss';
</style>
-746
View File
@@ -1,746 +0,0 @@
<template>
<el-card class="mt10">
<el-form :inline="true" :model="formSearch" class="demo-form-inline">
<el-form-item label="服务项目">
<el-input
v-model="formSearch.goodsName"
style="max-width: 300px"
placeholder="请输入服务项目"
class="input-with-select"
/>
</el-form-item>
<el-form-item label="订单编号">
<el-input
v-model="formSearch.orderId"
style="max-width: 300px"
placeholder="订单编号"
class="input-with-select"
/>
</el-form-item>
<el-form-item label="订单状态">
<el-select v-model="formSearch.status" placeholder="订单状态" style="width: 200px">
<el-option label="全部" value=" " />
<el-option label="待服务" value="0" />
<el-option label="服务中" value="1" />
<el-option label="待付款" value="2" />
<el-option label="已完成" value="3" />
<el-option label="已取消" value="4" />
</el-select>
</el-form-item>
<!-- <el-form-item label="维修费用">-->
<!-- <el-input-->
<!-- v-model="formSearch.amount"-->
<!-- style="max-width: 300px"-->
<!-- placeholder="维修费用"-->
<!-- class="input-with-select"-->
<!-- />-->
<!-- </el-form-item>-->
<br>
<el-form-item label="年">
<el-date-picker
v-model="formSearch.year"
type="year"
placeholder="请选择年份"
:disabled-date="disablePastAndSpecificYear"
style="margin-right: 20px"
@clear="clearYearDate"
@change="isYearClick"
/>
</el-form-item>
<el-form-item label="月">
<el-date-picker
v-model="formSearch.month"
type="month"
placeholder="请选择月份"
:disabled="!formSearch.year"
:disabled-date="disablePastAndSpecificMonth"
@clear="clearMonthDate"
@change="isMonthClick"
:default-value="new Date(formatDate(formSearch.year).year, 1, 1)"
:arrow-control="true"
/>
</el-form-item>
<el-form-item label="日">
<el-date-picker
v-model="formSearch.day"
:disabled="!formSearch.month"
:disabled-date="disablePastAndSpecificDay"
type="date"
placeholder="请选择日期"
@clear="clearDay"
@change="isDayClick"
:default-value="new Date(formatDate(formSearch.year).year, formatDate(formSearch.month).month-1, 1)"
:arrow-control="true"
/>
</el-form-item>
<br>
<el-form-item label="用户姓名">
<el-input
v-model="formSearch.username"
style="max-width: 300px"
placeholder="用户姓名"
class="input-with-select"
/>
</el-form-item>
<el-form-item label="勘测工程师姓名">
<el-input
v-model="formSearch.surveyorsName"
style="max-width: 300px"
placeholder="工程师姓名"
class="input-with-select"
/>
</el-form-item>
<el-form-item label="维修工程师姓名">
<el-input
v-model="formSearch.repairerName"
style="max-width: 300px"
placeholder="工程师姓名"
class="input-with-select"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSearchSubmit">搜索</el-button>
</el-form-item>
<el-form-item style="float: right">
<el-button type="warning" @click="excelDown">导出</el-button>
</el-form-item>
</el-form>
<el-table
ref="table"
:data="tableData"
:default-sort="{ prop: 'date', order: 'descending' }"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
class="m10"
>
<el-table-column
label="编号"
prop="id"
width="120"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column
label="状态"
prop="status"
width="120"
align="center"
sortable
>
<template #default="scope">
<el-tag type="info" v-if="scope.row.status === 0">待服务</el-tag>
<el-tag type="warning" v-if="scope.row.status === 1">服务中</el-tag>
<el-tag type="danger" v-if="scope.row.status === 2">待付款 </el-tag>
<el-tag type="success" v-if="scope.row.status === 3">已完成</el-tag>
<el-tag type="info" style="color: #d54f50" v-if="scope.row.status === 4">已取消</el-tag>
</template>
</el-table-column>
<el-table-column
label="服务项目"
prop="goodsName"
width="150"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="预约时间"
prop="appointmentTime"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column
label="项目费用"
width="120"
align="center"
show-overflow-tooltip
sortable
>
<template #default="scope">
{{ formatPrice(scope.row.goodsPrice) }}元
</template>
</el-table-column>
<el-table-column
label="勘测工程师"
width="120"
align="center"
show-overflow-tooltip
sortable
>
<template #default="scope">
{{ scope.row.surveyorsName }}
</template>
</el-table-column>
<el-table-column
label="维修工程师"
width="120"
align="center"
show-overflow-tooltip
sortable
>
<template #default="scope">
<template v-if="scope.row.repairerName">
{{ scope.row.repairerName }}
</template>
<template v-else>
<el-tag type="info">未分配</el-tag>
</template>
</template>
</el-table-column>
<el-table-column
label="报价费用"
width="120"
align="center"
show-overflow-tooltip
sortable
>
<template #default="scope">
<template v-if="scope.row.amount > 0">
{{ formatPrice(scope.row.amount) }}元
</template>
<template v-else>
<el-tag type="info">暂未报价</el-tag>
</template>
</template>
</el-table-column>
<el-table-column
label="用户姓名"
prop="username"
width="300"
align="center"
show-overflow-tooltip
/>
<el-table-column label="头像" width="200" align="center">
<template #default="scope">
<el-avatar :size="50" :src="scope.row.avatar" />
</template>
</el-table-column>
<el-table-column
label="下单时间"
prop="createTime"
width="auto"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column
label="付款时间"
prop="completionTime"
width="auto"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column label="操作" width="280px" align="center">
<template v-slot:default="scope">
<el-button type="info" @click="detail(scope.row)">详情</el-button>
<!-- <el-button type="danger">退款</el-button>-->
</template>
</el-table-column>
</el-table>
<el-pagination
size="small"
background
layout="prev, pager, next"
:total="tableData.length"
class="mt-4 mt10"
@current-change="handleCurrentChange"
/>
<el-drawer v-model="drawer">
<template #header>
<h4>订单详情</h4>
</template>
<template #default>
<el-descriptions
class="margin-top"
title="订单信息"
:column="3"
size="small"
border
style="margin-bottom: 20px"
>
<el-descriptions-item>
<template #label>
<div class="cell-item">
订单编号
</div>
</template>
{{detailData.id}}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
订单状态
</div>
</template>
<el-tag type="info" v-if="detailData.status === 0">待服务</el-tag>
<el-tag type="warning" v-if="detailData.status === 1">服务中</el-tag>
<el-tag type="danger" v-if="detailData.status === 2">待付款 </el-tag>
<el-tag type="success" v-if="detailData.status === 3">已完成</el-tag>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
预约费用
</div>
</template>
{{ formatPrice(detailData.goodsPrice) }}元
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
报价费用
</div>
</template>
<template v-if="detailData.amount > 0">
{{ formatPrice(detailData.amount) }}元
</template>
<template v-else>
<el-tag type="info">暂未报价</el-tag>
</template>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
预约时间
</div>
</template>
{{detailData.appointmentTime}}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
付款时间
</div>
</template>
{{detailData.completionTime}}
</el-descriptions-item>
</el-descriptions>
<el-descriptions
class="margin-top"
title="客户信息"
:column="3"
size="small"
border
style="margin-bottom: 20px"
>
<el-descriptions-item label="微信昵称">{{ detailData.username }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ detailData.mobile }}</el-descriptions-item>
<el-descriptions-item label="地址">
{{ detailData.address }}
</el-descriptions-item>
</el-descriptions>
<el-descriptions
class="margin-top"
title="勘测工程师信息"
:column="3"
size="small"
border
style="margin-bottom: 20px"
>
<el-descriptions-item label="名字">{{ detailData.surveyorsName }}</el-descriptions-item>
<el-descriptions-item label="联系方式">{{ detailData.surveyorsMobile }}</el-descriptions-item>
<el-descriptions-item label="预约时间">{{ detailData.appointmentTime }}</el-descriptions-item>
</el-descriptions>
<el-descriptions
class="margin-top"
title="维修工程师信息"
:column="3"
size="small"
border
style="margin-bottom: 20px"
>
<el-descriptions-item label="名字">{{ detailData.repairerName }}</el-descriptions-item>
<el-descriptions-item label="联系方式">{{ detailData.repairerMobile }}</el-descriptions-item>
<el-descriptions-item label="预约时间">{{ detailData.maintenanceTime }}</el-descriptions-item>
</el-descriptions>
<div style="display: flex;justify-content: flex-end;margin-top: 50px">
<el-button @click="drawer = false">取消</el-button>
<!-- <el-button type="danger" @click="confirmClick">退款</el-button>-->
</div>
</template>
</el-drawer>
</el-card>
</template>
<script setup>
import {nextTick, onMounted, reactive, ref} from 'vue'
import {exportOrder, getOrderList} from "../../api/modules/order";
import {ElMessage} from "element-plus";
const tableData = ref([])
const table = ref()
const disabled = ref(false)
const dialogVisible = ref(false)
const total = ref(0)
const searchName = ref('');
const drawer = ref(false)
const formSearch = ref({
goodsName: '',
orderId: '',
status: ' ',
amount: '',
username: '',
surveyorsName: '',
repairerName: '',
month: '',
year: '',
day: '',
page: 1,
size: 10,
current: 1,
})
const detailData = ref();
const isStatus = ref('');
// 初始化数据
const initData = () => {
getOrderList(formSearch.value).then((res) => {
tableData.value = res.data.records
total.value = res.data.total
})
}
// 格式化价格
const formatPrice = (price) => {
price = price == null ? price = 0 : price;
return parseFloat(price).toFixed(2);
}
// 订单详情
const detail = (row) => {
drawer.value = true
detailData.value = { ...row }
console.log('detailData', detailData.value);
}
const handleCurrentChange = (val) => {
formSearch.value.size = 10
formSearch.value.page = val
initData(formSearch.value)
}
// 清空年份
const clearYearDate = () => {
formSearch.value.year = ''
}
// 清空月份
const clearMonthDate = () => {
formSearch.value.month = ''
}
// 清空日期
const clearDay = () => {
formSearch.value.day = ''
}
// 禁止选择之后的年份
const disablePastAndSpecificYear = (date) => {
// 获取当前日期
const currentDate = new Date();
currentDate.setDate(currentDate.getDate() - 1);
// 禁止选择今天的前一天及之前的日期(不包含今天)
if (date > currentDate) {
return true;
}
// 禁止选择特定的未来日期,例如节假日
const disabledDates = [new Date(2023, 9, 1), new Date(2023, 10, 1)];
return disabledDates.some((disabledDate) => {
return (
date.getFullYear() === disabledDate.getFullYear() &&
date.getMonth() === disabledDate.getMonth() &&
date.getDate() === disabledDate.getDate()
);
});
};
// 选中年份
const isYearClick = () => {
formSearch.value.month = '';
formSearch.value.day = '';
}
// 选中月份
const isMonthClick = () => {
formSearch.value.day = '';
}
// 选中天
const isDayClick = () => {
}
// 选中月份禁止调整年份
const disablePastAndSpecificMonth = (date) => {
if (!formSearch.value.year) {
return true; // 未选择年份时,禁用所有月份
}
const selectedYear = formatDate(formSearch.value.year).year;
const year = date.getFullYear();
// 只允许选择选中年份的月份
if (year !== selectedYear) {
return true;
}
return false;
};
// 选中年月禁止调整天
const disablePastAndSpecificDay = (date) => {
if (!formSearch.value.month) {
return true; // 未选择月份时,禁用所有日期
}
const selectedYear = formatDate(formSearch.value.year).year;
const selectedMonth = formatDate(formSearch.value.month).month;
const year = date.getFullYear();
const month = date.getMonth()+1;
if (year !== selectedYear || month != selectedMonth) {
return true;
}
return false;
}
const excelDown = async () => {
const url = downloadFile();
const currentDate = new Date().toISOString().split('T')[0]; // 获取当前日期,格式为 YYYY-MM-DD
const randomNum = generateRandomNumber();
try {
const response = await fetch(url, {
method: 'GET',
headers: {
'Authorization': "Bearer " + localStorage.getItem("token"), // 替换为实际的 token
'Content-Type': 'application/json'
}
});
const blob = await response.blob();
const downloadUrl = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = downloadUrl;
a.download = `${formatDate(currentDate)}-${randomNum}.xlsx`; // 设置下载文件的名称
a.click();
window.URL.revokeObjectURL(downloadUrl);
} catch (error) {
console.error('Error downloading file:', error);
}
};
const generateRandomNumber = () => {
return Math.floor(Math.random() * 10000); // 生成一个 0 到 9999 之间的随机数
};
// 导出文件事件
const downloadFile = () => {
let params = {...formSearch.value}
if(params.status !== ' ')
{
params.status = parseInt(params.status, 10);
}else{
delete params.status;
}
if(params.year !== '')
{
let {
year
} = {...formatDate(params.year)};
params.year = year;
}else{
delete params.year;
}
if(params.month !== '')
{
let {
month
} = {...formatDate(params.month)};
params.month = month;
}else{
delete params.month;
}
if(params.day !== '')
{
let {
year,
month,
day
} = {...formatDate(params.day)};
params.year = year;
params.month = month;
params.day = day;
}else{
delete params.day;
}
return exportOrder(params);
}
// 搜索事件
const onSearchSubmit = ()=> {
let params = {...formSearch.value}
if(params.status !== ' ')
{
params.status = parseInt(params.status, 10);
}else{
delete params.status;
}
if(params.year !== '')
{
let {
year
} = {...formatDate(params.year)};
params.year = year;
}else{
delete params.year;
}
if(params.month !== '')
{
let {
month
} = {...formatDate(params.month)};
params.month = month;
}else{
delete params.month;
}
if(params.day !== '')
{
let {
year,
month,
day
} = {...formatDate(params.day)};
params.year = year;
params.month = month;
params.day = day;
}else{
delete params.day;
}
getOrderList(params).then((res) => {
tableData.value = res.data.records
total.value = res.data.total
})
};
// 日期格式
const formatDate = (date) => {
if(date === '')
{
return {
year: 1999,
month: 1,
day: 1,
};
}
if (typeof date === 'string') {
// 检查是否已经是格式化的字符串
const regex = /^\d{4}-\d{2}-\d{2}$/;
if (regex.test(date)) {
return date; // 已经是格式化的字符串,直接返回
}
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return {
year: year,
month: month,
day: day,
};
};
onMounted(() => {
initData()
})
</script>
<style lang="scss" scoped>
</style>
-86
View File
@@ -1,86 +0,0 @@
export const options = [
{
userId: 1,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '高永建',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},
{
userId: 2,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '张三',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-10 10:11:01'
},
{
userId: 3,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '李四',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-13 10:11:01'
},
{
userId: 4,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-02 10:11:01'
},{
userId: 5,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-01 10:11:01'
},
{
userId: 6,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},{
userId: 7,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},{
userId: 8,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},{
userId: 9,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},{
userId: 10,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},
{
userId: 11,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},
];
-11
View File
@@ -1,11 +0,0 @@
<script setup>
</script>
<template>
</template>
<style scoped lang="scss">
</style>
-562
View File
@@ -1,562 +0,0 @@
<template>
<el-card class="mt10">
<el-drawer v-model="drawer" :direction="direction" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :show-close="false">
<template #header>
<h4 v-if="!editStatus">创建排班</h4>
<h4 v-else>更新排班</h4>
</template>
<template #default>
<el-form :model="scheduleForm" label-width="auto" style="max-width: 600px">
<el-form-item label="日期时间">
<el-date-picker
v-if="!editStatus"
v-model="scheduleForm.date"
type="date"
placeholder="排班日期"
:disabled-date="disablePastAndSpecificDates"
style="margin-right: 20px"
@change="handleDateChange"
/>
<el-date-picker
v-else
v-model="scheduleForm.date"
type="date"
placeholder="排班日期"
:disabled-date="disablePastAndSpecificDates"
style="margin-right: 20px"
@change="handleDateChange"
disabled
/>
<el-select
v-model="scheduleForm.timeQuantumId"
filterable
placeholder="请选择排班时间"
style="width: 240px"
@change="handleDateChange"
>
<el-option
v-for="item in timeDataList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="排班人员">
<template v-if="!editStatus">
<template v-if="userList.length">
<el-checkbox-group v-model="scheduleForm.userids" size="large">
<el-checkbox-button v-for="item in userList" :key="item.id" :value="item.id">
{{ item.nickName }}
</el-checkbox-button>
</el-checkbox-group>
</template>
<template v-else>
<el-alert title="选择排班日期时间后,将会获取排班人员" type="warning" />
</template>
</template>
<template v-else>
<el-tag type="info">{{scheduleForm.username}}</el-tag>
</template>
</el-form-item>
<div style="display: flex;justify-content: center;margin-top: 50px">
<el-button @click="handleCancelSchedule">取消</el-button>
<el-button type="success" @click="handleSaveSchedule">确认</el-button>
</div>
</el-form>
</template>
</el-drawer>
<el-container class="mt10" style="height: 80vh">
<el-aside width="220px">
<el-scrollbar>
<el-menu >
<el-sub-menu v-for="(dateItem, index) in dateList" :index="index.toString()" :key="index">
<template #title>
<el-icon><Calendar /></el-icon>
<template v-if="defaultOpeneds === index">
<b>今天:</b> {{ dateItem }}
</template>
<template v-else>
{{ dateItem }}
</template>
</template>
<el-menu-item-group>
<el-menu-item v-for="(timeItem, timeIndex) in timeList" :key="timeItem.id" :index="index.toString() + '-' + timeIndex.toString()" @click="selectTimeClick(dateItem, timeItem)">
{{timeItem.startTime}} - {{timeItem.endTime}}
</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
</el-scrollbar>
</el-aside>
<el-container class="ml20">
<el-main>
<el-button type="success" @click="drawer = true" class="mR10">
<el-icon style="margin-right: 10px;"><CirclePlus /></el-icon>
创建排班
</el-button>
<el-tag type="success" class="mR10">当前日期:{{ isDate }}</el-tag>
<el-tag type="info" class="mR10" v-if="isRangeTime">时间段:{{isRangeTime}}</el-tag>
<el-scrollbar class="mt20">
<el-table :data="userDataList">
<el-table-column prop="date" label="日期" width="200" />
<el-table-column prop="time" label="时间段" width="200" />
<el-table-column prop="id" label="ID" width="200" />
<el-table-column prop="username" label="名称" width="120" />
<el-table-column label="头像" width="200" align="center">
<template #default="scope">
<el-avatar :size="50" :src="scope.row.avatar" />
</template>
</el-table-column>
<el-table-column prop="mobile" label="手机号" />
<el-table-column label="操作" width="280px" align="center">
<template v-slot:default="scope">
<el-button type="info" @click="editClick(scope.row)">编辑</el-button>
<el-popconfirm title="确认删除这个排班吗?" @confirm="delQuantumClick(scope.row)">
<template #reference>
<el-button type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-scrollbar>
</el-main>
</el-container>
</el-container>
</el-card>
</template>
<script setup>
import { onMounted, ref, nextTick } from 'vue';
import {Menu as IconMenu, Message, Setting, Calendar, CirclePlus} from '@element-plus/icons-vue';
import {delQuantum, listQuantum} from "../../api/modules/schedulingTime";
import {ElMessage} from "element-plus";
import {addSchedule, delSchedule, getScheduleList, updateSchedule} from "../../api/modules/scheduling";
import {listMaintenanceUser, listSurveyorsUser} from "../../api/modules/schedulingUser";
const scheduleForm = ref({
userids: [],
roleId: 3,
date: '',
timeQuantumId: '',
});
const direction = ref('rtl')
const drawer = ref(false)
const editStatus = ref(false)
const userList = ref([]); // 勘测人员列表
// 日期列表
const dateList = ref([]);
const timeList = ref([]); // 时间段
const timeDataList = ref([]); // 时间段
const defaultOpeneds = ref([]);
const userDataList = ref([]); // 已排期用户
const isDate = ref(''); // 选中的日期
const istimeQuantumId = ref(''); // 时间段ID
const isRangeTime = ref(''); // 时间段
// 初始化
const initData = () => {
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentMonth = currentDate.getMonth();
// 上个月的第一天和最后一天
const lastMonthFirstDay = new Date(currentYear, currentMonth - 1, 1);
const lastMonthLastDay = new Date(currentYear, currentMonth, 0);
// 这个月的第一天和最后一天
const thisMonthFirstDay = new Date(currentYear, currentMonth, 1);
const thisMonthLastDay = new Date(currentYear, currentMonth + 1, 0);
// 下个月的第一天和最后一天
const nextMonthFirstDay = new Date(currentYear, currentMonth + 1, 1);
const nextMonthLastDay = new Date(currentYear, currentMonth + 2, 0);
// 添加上个月的日期
// for (let d = lastMonthFirstDay; d <= lastMonthLastDay; d.setDate(d.getDate() + 1)) {
// dateList.value.push(formatDate(new Date(d)));
// }
// 添加这个月的日期
for (let d = thisMonthFirstDay; d <= thisMonthLastDay; d.setDate(d.getDate() + 1)) {
dateList.value.push(formatDate(new Date(d)));
}
// 添加下个月的日期
for (let d = nextMonthFirstDay; d <= nextMonthLastDay; d.setDate(d.getDate() + 1)) {
dateList.value.push(formatDate(new Date(d)));
}
// 找到今天的日期在 dateList 中的索引
const todayIndex = dateList.value.indexOf(formatDate(currentDate));
if (todayIndex !== -1) {
defaultOpeneds.value = todayIndex;
}
isDate.value = formatDate(currentDate); // 今天
scheduleForm.value.date = formatDate(currentDate); // 默认的日期
// 获取排班时段
listQuantum().then((res) => {
timeList.value = res.data;
timeDataList.value = res.data.map(item => ({
value: item.id,
label: `${item.startTime}-${item.endTime}`
}));
initSelectTimeClick(formatDate(currentDate), timeList.value);// 获取当天所有时段人员
})
};
// 监听选中状态
const handleDateChange = (value) => {
if (editStatus.value) {
return false;
} // 编辑的时候无需获取
if (!scheduleForm.value.date) {
scheduleForm.value.timeQuantumId = '';
ElMessage({
type: 'warning',
message: '请先选择排班日期'
});
return;
}
if (!scheduleForm.value.timeQuantumId) {
ElMessage({
type: 'warning',
message: '请继续选择排班时间段'
});
return;
}
// 查询勘测人员列表
let params = {
date: formatDate(scheduleForm.value.date),
timeQuantumId: scheduleForm.value.timeQuantumId
};
userList.value = [];
listMaintenanceUser(params).then((res) => {
userList.value = res.data
});
}
// 添加排班人员
const handleSaveSchedule = () => {
// 如果不是编辑,则是添加,如果是编辑,则是更新
if (!editStatus.value) {
if (!scheduleForm.value.date) {
ElMessage({
type: 'warning',
message: '请选择排班日期'
});
return;
}
if (!scheduleForm.value.timeQuantumId) {
ElMessage({
type: 'warning',
message: '请选择排版时段'
});
return;
}
if (scheduleForm.value.userids.length < 1) {
ElMessage({
type: 'warning',
message: '请选择人员'
});
return;
}
scheduleForm.value.date = formatDate(scheduleForm.value.date); //转换日期
// 添加人员
addSchedule(scheduleForm.value).then((res) => {
if (res.code === 200) {
if (!istimeQuantumId.value) {
initSelectTimeClick(scheduleForm.value.date, timeList.value);// 获取当天所有时段人员
} else {
let dateParams = timeList.value.filter(item => item.id === scheduleForm.value.timeQuantumId);
selectTimeClick(scheduleForm.value.date, {
id: istimeQuantumId.value,
startTime: dateParams[0].startTime,
endTime: dateParams[0].endTime
});// 获取当天所有时段人员
}
scheduleForm.value = {
userids: [],
roleId: 3,
date: '',
timeQuantumId: '',
}
drawer.value = false;
editStatus.value = false;
ElMessage({
type: 'success',
message: '新增成功!'
});
}
})
} else {
let params = {
id: scheduleForm.value.id,
userid: scheduleForm.value.userid,
date: scheduleForm.value.date,
timeQuantumId: scheduleForm.value.timeQuantumId,
status: true
};
// 修改时间段
updateSchedule(params).then(res => {
if (res.code === 200) {
if (!istimeQuantumId.value) {
initSelectTimeClick(scheduleForm.value.date, timeList.value);// 获取当天所有时段人员
} else {
let dateParams = timeList.value.filter(item => item.id === params.timeQuantumId);
selectTimeClick(params.date, {
id: istimeQuantumId.value,
startTime: dateParams[0].startTime,
endTime: dateParams[0].endTime
});// 获取当天所有时段人员
}
scheduleForm.value = {
userids: [],
roleId: 3,
date: '',
timeQuantumId: '',
}
drawer.value = false;
editStatus.value = false;
ElMessage({
type: 'success',
message: '更新成功!'
});
}
});
}
};
// 取消添加排班人员
const handleCancelSchedule = () => {
drawer.value = false;
editStatus.value = false;
scheduleForm.value = {
userids: [],
roleId: 3,
date: '',
timeQuantumId: '',
};
};
// 禁止选择之前的日期
const disablePastAndSpecificDates = (date) => {
// 获取当前日期
const currentDate = new Date();
currentDate.setDate(currentDate.getDate() - 1);
// 禁止选择今天的前一天及之前的日期(不包含今天)
if (date < currentDate) {
return true;
}
// 禁止选择特定的未来日期,例如节假日
const disabledDates = [new Date(2023, 9, 1), new Date(2023, 10, 1)];
return disabledDates.some((disabledDate) => {
return (
date.getFullYear() === disabledDate.getFullYear() &&
date.getMonth() === disabledDate.getMonth() &&
date.getDate() === disabledDate.getDate()
);
});
};
// 获取当天时间段所有人员
const initSelectTimeClick = (dateItem, timeList) => {
let params = {
date: dateItem,
roleId: 3,
}
userDataList.value = [];
timeList.map(item => {
let params = {
date: dateItem,
roleId: 3,
timeQuantumId: item.id
}
// 获取用户数据
getScheduleList(params).then((res) => {
if (res.data.length) {
res.data.map(resItem => {
resItem.date = params.date;
resItem.time = item.startTime + '-' + item.endTime;
userDataList.value.push(resItem);
})
}
})
})
}
// 获取用户列表
const selectTimeClick = (dateItem, timeItem) => {
let params = {
date: dateItem,
roleId: 3,
timeQuantumId: timeItem.id
};
userDataList.value = [];
scheduleForm.value.date = dateItem; // 选中的日期
isDate.value = dateItem; // 选中的日期
istimeQuantumId.value = timeItem.id; // 选中的时间段id
isRangeTime.value = timeItem.startTime + '-' + timeItem.endTime; // 选中的时间段时间
getScheduleList(params).then((res) => {
res.data.map(resItem => {
resItem.date = params.date;
resItem.time = timeItem.startTime + '-' + timeItem.endTime;
userDataList.value.push(resItem);
})
})
}
// 日期格式
const formatDate = (date) => {
if (typeof date === 'string') {
// 检查是否已经是格式化的字符串
const regex = /^\d{4}-\d{2}-\d{2}$/;
if (regex.test(date)) {
return date; // 已经是格式化的字符串,直接返回
}
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
// 删除排班
const delQuantumClick = (row) => {
let params = {
id: row.id,
date: row.date
};
// 删除数据
delSchedule(params).then((res) => {
if (res.code === 200) {
if (!istimeQuantumId.value) {
initSelectTimeClick(params.date, timeList.value);// 获取当天所有时段人员
} else {
let dateParams = timeList.value.filter(item => item.id === istimeQuantumId.value);
selectTimeClick(params.date, {
id: istimeQuantumId.value,
startTime: dateParams[0].startTime,
endTime: dateParams[0].endTime
});// 获取当天所有时段人员
}
ElMessage({
type: 'success',
message: '删除成功'
});
}
});
}
// 编辑数据
const editClick = (row) => {
editStatus.value = true;
drawer.value = true;
scheduleForm.value = {...row}
}
onMounted(() => {
initData();
});
</script>
<style scoped>
.mt10 {
margin-top: 10px;
}
.ml20 {
margin-left: 20px;
}
</style>
-557
View File
@@ -1,557 +0,0 @@
<template>
<el-card class="mt10">
<el-drawer v-model="drawer" :direction="direction" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :show-close="false">
<template #header>
<h4 v-if="!editStatus">创建排班</h4>
<h4 v-else>更新排班</h4>
</template>
<template #default>
<el-form :model="scheduleForm" label-width="auto" style="max-width: 600px">
<el-form-item label="日期时间">
<el-date-picker
v-if="!editStatus"
v-model="scheduleForm.date"
type="date"
placeholder="排班日期"
:disabled-date="disablePastAndSpecificDates"
style="margin-right: 20px"
@change="handleDateChange"
/>
<el-date-picker
v-else
v-model="scheduleForm.date"
type="date"
placeholder="排班日期"
:disabled-date="disablePastAndSpecificDates"
style="margin-right: 20px"
@change="handleDateChange"
disabled
/>
<el-select
v-model="scheduleForm.timeQuantumId"
filterable
placeholder="请选择排班时间"
style="width: 240px"
@change="handleDateChange"
>
<el-option
v-for="item in timeDataList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="排班人员">
<template v-if="!editStatus">
<template v-if="userList.length">
<el-checkbox-group v-model="scheduleForm.userids" size="large">
<el-checkbox-button v-for="item in userList" :key="item.id" :value="item.id">
{{ item.nickName }}
</el-checkbox-button>
</el-checkbox-group>
</template>
<template v-else>
<el-alert title="选择排班日期时间后,将会获取排班人员" type="warning" />
</template>
</template>
<template v-else>
<el-tag type="info">{{scheduleForm.username}}</el-tag>
</template>
</el-form-item>
<div style="display: flex;justify-content: center;margin-top: 50px">
<el-button @click="handleCancelSchedule">取消</el-button>
<el-button type="success" @click="handleSaveSchedule">确认</el-button>
</div>
</el-form>
</template>
</el-drawer>
<el-container class="mt10" style="height: 80vh">
<el-aside width="220px">
<el-scrollbar>
<el-menu >
<el-sub-menu v-for="(dateItem, index) in dateList" :index="index.toString()" :key="index">
<template #title>
<el-icon><Calendar /></el-icon>
<template v-if="defaultOpeneds === index">
<b>今天:</b> {{ dateItem }}
</template>
<template v-else>
{{ dateItem }}
</template>
</template>
<el-menu-item-group>
<el-menu-item v-for="(timeItem, timeIndex) in timeList" :key="timeItem.id" :index="index.toString() + '-' + timeIndex.toString()" @click="selectTimeClick(dateItem, timeItem)">
{{timeItem.startTime}} - {{timeItem.endTime}}
</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
</el-scrollbar>
</el-aside>
<el-container class="ml20">
<el-main>
<el-button type="success" @click="drawer = true" class="mR10">
<el-icon style="margin-right: 10px;"><CirclePlus /></el-icon>
创建排班
</el-button>
<el-tag type="success" class="mR10">当前日期:{{ isDate }}</el-tag>
<el-tag type="info" class="mR10" v-if="isRangeTime">时间段:{{isRangeTime}}</el-tag>
<el-scrollbar class="mt20">
<el-table :data="userDataList">
<el-table-column prop="date" label="日期" width="200" />
<el-table-column prop="time" label="时间段" width="200" />
<el-table-column prop="id" label="ID" width="200" />
<el-table-column prop="username" label="名称" width="120" />
<el-table-column label="头像" width="200" align="center">
<template #default="scope">
<el-avatar :size="50" :src="scope.row.avatar" />
</template>
</el-table-column>
<el-table-column prop="mobile" label="手机号" />
<el-table-column label="操作" width="280px" align="center">
<template v-slot:default="scope">
<el-button type="info" @click="editClick(scope.row)">编辑</el-button>
<el-popconfirm title="确认删除这个排班吗?" @confirm="delQuantumClick(scope.row)">
<template #reference>
<el-button type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-scrollbar>
</el-main>
</el-container>
</el-container>
</el-card>
</template>
<script setup>
import { onMounted, ref, nextTick } from 'vue';
import {Menu as IconMenu, Message, Setting, Calendar, CirclePlus} from '@element-plus/icons-vue';
import {delQuantum, listQuantum} from "../../api/modules/schedulingTime";
import {ElMessage} from "element-plus";
import {addSchedule, delSchedule, getScheduleList, updateSchedule} from "../../api/modules/scheduling";
import {listSurveyorsUser} from "../../api/modules/schedulingUser";
const scheduleForm = ref({
userids: [],
roleId: 2,
date: '',
timeQuantumId: '',
});
const direction = ref('rtl')
const drawer = ref(false)
const editStatus = ref(false)
const userList = ref([]); // 勘测人员列表
// 日期列表
const dateList = ref([]);
const timeList = ref([]); // 时间段
const timeDataList = ref([]); // 时间段
const defaultOpeneds = ref([]);
const userDataList = ref([]); // 已排期用户
const isDate = ref(''); // 选中的日期
const istimeQuantumId = ref(''); // 时间段ID
const isRangeTime = ref(''); // 时间段
// 初始化
const initData = () => {
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentMonth = currentDate.getMonth();
// 上个月的第一天和最后一天
const lastMonthFirstDay = new Date(currentYear, currentMonth - 1, 1);
const lastMonthLastDay = new Date(currentYear, currentMonth, 0);
// 这个月的第一天和最后一天
const thisMonthFirstDay = new Date(currentYear, currentMonth, 1);
const thisMonthLastDay = new Date(currentYear, currentMonth + 1, 0);
// 下个月的第一天和最后一天
const nextMonthFirstDay = new Date(currentYear, currentMonth + 1, 1);
const nextMonthLastDay = new Date(currentYear, currentMonth + 2, 0);
// 添加上个月的日期
// for (let d = lastMonthFirstDay; d <= lastMonthLastDay; d.setDate(d.getDate() + 1)) {
// dateList.value.push(formatDate(new Date(d)));
// }
// 添加这个月的日期
for (let d = thisMonthFirstDay; d <= thisMonthLastDay; d.setDate(d.getDate() + 1)) {
dateList.value.push(formatDate(new Date(d)));
}
// 添加下个月的日期
for (let d = nextMonthFirstDay; d <= nextMonthLastDay; d.setDate(d.getDate() + 1)) {
dateList.value.push(formatDate(new Date(d)));
}
// 找到今天的日期在 dateList 中的索引
const todayIndex = dateList.value.indexOf(formatDate(currentDate));
if (todayIndex !== -1) {
defaultOpeneds.value = todayIndex;
}
isDate.value = formatDate(currentDate); // 今天
scheduleForm.value.date = formatDate(currentDate); // 默认的日期
// 获取排班时段
listQuantum().then((res) => {
timeList.value = res.data;
timeDataList.value = res.data.map(item => ({
value: item.id,
label: `${item.startTime}-${item.endTime}`
}));
initSelectTimeClick(formatDate(currentDate), timeList.value);// 获取当天所有时段人员
})
};
// 监听选中状态
const handleDateChange = (value) => {
if(editStatus.value){return false;} // 编辑的时候无需获取
if(!scheduleForm.value.date)
{
scheduleForm.value.timeQuantumId = '';
ElMessage({
type: 'warning',
message: '请先选择排班日期'
});
return;
}
if(!scheduleForm.value.timeQuantumId)
{
ElMessage({
type: 'warning',
message: '请继续选择排班时间段'
});
return;
}
// 查询勘测人员列表
let params = {
date: formatDate(scheduleForm.value.date),
timeQuantumId: scheduleForm.value.timeQuantumId
};
userList.value = [];
listSurveyorsUser(params).then((res)=>{
userList.value = res.data
});
}
// 添加排班人员
const handleSaveSchedule = () => {
// 如果不是编辑,则是添加,如果是编辑,则是更新
if(!editStatus.value)
{
if(!scheduleForm.value.date){
ElMessage({
type: 'warning',
message: '请选择排班日期'
});
return;
}
if(!scheduleForm.value.timeQuantumId){
ElMessage({
type: 'warning',
message: '请选择排版时段'
});
return;
}
if(scheduleForm.value.userids.length < 1){
ElMessage({
type: 'warning',
message: '请选择人员'
});
return;
}
scheduleForm.value.date = formatDate(scheduleForm.value.date); //转换日期
// 添加人员
addSchedule(scheduleForm.value).then((res) => {
if(res.code === 200)
{
if(!istimeQuantumId.value)
{
initSelectTimeClick(scheduleForm.value.date, timeList.value);// 获取当天所有时段人员
}else{
let dateParams = timeList.value.filter(item => item.id === scheduleForm.value.timeQuantumId);
selectTimeClick(scheduleForm.value.date, {id:istimeQuantumId.value, startTime:dateParams[0].startTime, endTime:dateParams[0].endTime});// 获取当天所有时段人员
}
scheduleForm.value = {
userids: [],
roleId: 2,
date: '',
timeQuantumId: '',
}
drawer.value = false;
editStatus.value = false;
ElMessage({
type: 'success',
message: '新增成功!'
});
}
})
}else{
let params = {
id: scheduleForm.value.id,
userid: scheduleForm.value.userid,
date: scheduleForm.value.date,
timeQuantumId: scheduleForm.value.timeQuantumId,
status: true
};
// 修改时间段
updateSchedule(params).then(res => {
if(res.code === 200)
{
if(!istimeQuantumId.value)
{
initSelectTimeClick(scheduleForm.value.date, timeList.value);// 获取当天所有时段人员
}else{
let dateParams = timeList.value.filter(item => item.id === params.timeQuantumId);
selectTimeClick(params.date, {id:istimeQuantumId.value, startTime:dateParams[0].startTime, endTime:dateParams[0].endTime});// 获取当天所有时段人员
}
scheduleForm.value = {
userids: [],
roleId: 2,
date: '',
timeQuantumId: '',
}
drawer.value = false;
editStatus.value = false;
ElMessage({
type: 'success',
message: '更新成功!'
});
}
});
}
};
// 取消添加排班人员
const handleCancelSchedule = () => {
drawer.value = false;
editStatus.value = false;
scheduleForm.value = {
userids: [],
roleId: 2,
date: '',
timeQuantumId: '',
};
};
// 禁止选择之前的日期
const disablePastAndSpecificDates = (date) => {
// 获取当前日期
const currentDate = new Date();
currentDate.setDate(currentDate.getDate() - 1);
// 禁止选择今天的前一天及之前的日期(不包含今天)
if (date < currentDate) {
return true;
}
// 禁止选择特定的未来日期,例如节假日
const disabledDates = [new Date(2023, 9, 1), new Date(2023, 10, 1)];
return disabledDates.some((disabledDate) => {
return (
date.getFullYear() === disabledDate.getFullYear() &&
date.getMonth() === disabledDate.getMonth() &&
date.getDate() === disabledDate.getDate()
);
});
};
// 获取当天时间段所有人员
const initSelectTimeClick = (dateItem, timeList) => {
let params = {
date: dateItem,
roleId: 2,
}
userDataList.value = [];
timeList.map(item => {
let params = {
date: dateItem,
roleId: 2,
timeQuantumId: item.id
}
// 获取用户数据
getScheduleList(params).then((res) => {
if(res.data.length)
{
res.data.map(resItem => {
resItem.date = params.date;
resItem.time = item.startTime + '-' + item.endTime;
userDataList.value.push(resItem);
})
}
})
})
}
// 获取用户列表
const selectTimeClick = (dateItem, timeItem) => {
let params = {
date: dateItem,
roleId: 2,
timeQuantumId: timeItem.id
};
userDataList.value = [];
scheduleForm.value.date = dateItem; // 选中的日期
isDate.value = dateItem; // 选中的日期
istimeQuantumId.value = timeItem.id; // 选中的时间段id
isRangeTime.value = timeItem.startTime + '-' + timeItem.endTime; // 选中的时间段时间
getScheduleList(params).then((res) => {
res.data.map(resItem => {
resItem.date = params.date;
resItem.time = timeItem.startTime + '-' + timeItem.endTime;
userDataList.value.push(resItem);
})
})
}
// 日期格式
const formatDate = (date) => {
if (typeof date === 'string') {
// 检查是否已经是格式化的字符串
const regex = /^\d{4}-\d{2}-\d{2}$/;
if (regex.test(date)) {
return date; // 已经是格式化的字符串,直接返回
}
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
// 删除排班
const delQuantumClick = (row) => {
let params = {
id:row.id,
date: row.date
};
// 删除数据
delSchedule(params).then((res) => {
if(res.code === 200)
{
if(!istimeQuantumId.value)
{
initSelectTimeClick(params.date, timeList.value);// 获取当天所有时段人员
}else{
let dateParams = timeList.value.filter(item => item.id === istimeQuantumId.value);
selectTimeClick(params.date, {id:istimeQuantumId.value, startTime:dateParams[0].startTime, endTime:dateParams[0].endTime});// 获取当天所有时段人员
}
ElMessage({
type: 'success',
message: '删除成功'
});
}
});
}
// 编辑数据
const editClick = (row) => {
editStatus.value = true;
drawer.value = true;
scheduleForm.value = {...row}
}
onMounted(() => {
initData();
});
</script>
<style scoped>
.mt10 {
margin-top: 10px;
}
.ml20 {
margin-left: 20px;
}
</style>
-303
View File
@@ -1,303 +0,0 @@
<template>
<el-card class="mt10">
<el-button type="success" @click="drawer = true">
<el-icon style="margin-right: 10px;"><CirclePlus /></el-icon>
创建时段
</el-button>
<el-drawer v-model="drawer" :direction="direction" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :show-close="false">
<template #header>
<h4 v-if="!editStatus">创建排班</h4>
<h4 v-else>更新排班</h4>
</template>
<template #default>
<el-form :model="formData" label-width="auto" style="max-width: 600px">
<el-form-item label="开始时间">
<el-time-select
v-model="formData.startTime"
:max-time="formData.endTime"
class="time-select"
placeholder="选择开始时间"
start="00:00:00"
end="23:59:59"
step="00:30:00"
format="HH:mm:ss"
/>
</el-form-item>
<el-form-item label="结束时间">
<el-time-select
v-model="formData.endTime"
:min-time="formData.startTime"
placeholder="结束时间"
start="00:00:00"
end="23:59:59"
step="00:30:00"
format="HH:mm:ss"
/>
</el-form-item>
<div style="display: flex;justify-content: center;margin-top: 50px">
<el-button @click="handleCancel">取消</el-button>
<el-button type="success" @click="handleSave">确认</el-button>
</div>
</el-form>
</template>
</el-drawer>
<el-table
ref="table"
:data="tableData"
:default-sort="{ prop: 'date', order: 'descending' }"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
class="mt20"
v-loading="loading"
>
<el-table-column
label="编号"
prop="id"
width="120"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column label="时段" align="center">
<template #default="scope">
{{scope.row.startTime}}-{{scope.row.endTime}}
</template>
</el-table-column>
<el-table-column label="操作" width="280px" align="center">
<template v-slot:default="scope">
<el-button type="info" @click="editClick(scope.row)">编辑</el-button>
<el-popconfirm title="确认删除这个时间段吗?" @confirm="delQuantumClick(scope.row)">
<template #reference>
<el-button type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
<script setup>
import {nextTick, onMounted, reactive, ref} from 'vue'
import {addQuantum, delQuantum, listQuantum, updateQuantum} from "../../api/modules/schedulingTime";
import {CirclePlus} from "@element-plus/icons-vue";
import {ElMessage} from "element-plus";
const tableData = ref([])
const table = ref()
const total = ref(0)
const drawer = ref(false)
const editStatus = ref(false)
const direction = ref('rtl');
const loading = ref(true)
const formData = ref({
startTime: '',
endTime:'',
flag: true
});
// 初始化数据
const initData = () => {
// 获取排班时段
listQuantum().then((res) => {
tableData.value = res.data
loading.value = false
})
}
// 取消
const handleCancel = () => {
drawer.value = false
formData.value = {
startTime: '',
endTime:'',
flag: false
};
}
// 提交数据
const handleSave = () => {
if(!formData.value.startTime){
ElMessage({
type: 'warning',
message: '请选择开始时间段'
});
return;
}
if(!formData.value.endTime){
ElMessage({
type: 'warning',
message: '请选择结束时间段'
});
return;
}
if(!editStatus.value)
{
// 添加时间段
addQuantum(formData.value).then(res => {
initData();
drawer.value = false;
formData.value = {
startTime: '',
endTime:'',
flag: false
};
ElMessage({
type: 'success',
message: '添加成功'
});
});
}else{
// 修改数据
updateQuantum(formData.value).then((res) => {
editStatus.value = false;
drawer.value = false;
ElMessage({
message: '修改成功',
type: 'success',
});
initData();
})
}
}
// 删除时间段
const delQuantumClick = (row) => {
let params = {
id:row.id
};
// 删除数据
delQuantum(params).then((res) => {
initData();
ElMessage({
type: 'success',
message: '删除成功'
});
});
}
// 编辑数据
const editClick = (row) => {
editStatus.value = true;
drawer.value = true;
formData.value = {...row}
}
// 启用禁用时间段
const upStatus = (row) => {
let formData = {...row}
// 修改数据
updateQuantum(formData).then((res) => {
if(formData.flag)
{
ElMessage({
message: '启用成功',
type: 'success',
});
}else{
ElMessage({
message: '禁用成功',
type: 'success',
});
}
initData();
})
}
onMounted(() => {
initData()
})
</script>
<style lang="scss" scoped>
.mt-4 {
float: right;
text-align: right;
margin-bottom: 20px;
}
.demo-form-inline {
}
.dragClass {
background: rgba($color: #41c21a, $alpha: 0.5) !important;
}
// 停靠
.ghostClass {
background: rgba($color: #6cacf5, $alpha: 0.5) !important;
}
// 选择
.chosenClass:hover > td {
background: rgba($color: #f56c6c, $alpha: 0.5) !important;
}
.icon-view {
font-size: 20px;
color: #673ab7;
margin: 0 10px;
}
.icon-edit {
font-size: 20px;
color: #2f60c2;
margin: 0 10px;
}
.icon-dele {
font-size: 20px;
color: #ff5722;
}
.btn-color {
background: #fff;
color: #4c60cc;
}
.expand-title {
padding: 10px;
color: #919399;
font-weight: 600;
}
</style>
+297
View File
@@ -0,0 +1,297 @@
<template>
<el-card shadow="never" class="henader-card">
<div class="flx-row">
<el-form :inline="true" :model="queryData" style="flex: 1">
<el-input placeholder="请输入搜索内容" v-model="queryData.keyWord">
</el-input>
<el-date-picker
class="ml20"
v-model="queryData.date"
type="datetimerange"
:shortcuts="shortcuts"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form>
<div class="flex-right">
<el-button type="primary" :icon="Search" @click="initData" class="ml20"
>搜索</el-button
>
<el-button type="primary" @click="dialogVisibleShow">+添加</el-button>
</div>
</div>
</el-card>
<el-card shadow="never">
<el-table
:data="tableData"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
border
stripe
style="width: 100%"
>
<el-table-column
v-for="item in options"
:key="item.type"
:prop="item.props"
:label="item.label"
:width="item.width"
:align="item.align"
show-overflow-tooltip
:fixed="item.fixed"
>
<template v-slot:default="scope" v-if="item.props === 'actions'">
<el-icon class="icon-view" @click="ItemView(scope.row)"
><View
/></el-icon>
<el-icon class="icon-edit" @click="editorClick(scope.row)"
><Edit
/></el-icon>
<el-popconfirm
confirm-button-text="确认"
cancel-button-text="取消"
:icon="InfoFilled"
icon-color="#626AEF"
title="确认删除该用户?"
@confirm="DeleteItem(index)"
>
<template #reference>
<el-icon class="icon-dele"><Delete /></el-icon>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
small
background
:page-size="queryData.size"
layout="prev, pager, next"
:total="total"
class="mt-4"
@current-change="handleCurrentChange"
/>
</el-card>
<el-dialog
v-model="dialogVisible"
:title="`${dialogData.title}用户`"
:width="dialogWidth"
:hide-required-asterisk="dialogData.isView"
draggable
>
<el-form
:model="dialogData.FormData"
:rules="rules"
ref="FormRef"
class="demo-ruleForm"
>
<el-form-item
label="用户名"
:label-width="formLabelWidth"
prop="username"
>
<el-input v-model="dialogData.FormData.username" autocomplete="off" />
</el-form-item>
<el-form-item label="邮箱" :label-width="formLabelWidth" prop="email">
<el-input v-model="dialogData.FormData.email" autocomplete="off" />
</el-form-item>
<el-form-item label="地址" :label-width="formLabelWidth" prop="address">
<el-input v-model="dialogData.FormData.address" type="textarea" />
</el-form-item>
<el-form-item label="备注" :label-width="formLabelWidth" prop="content">
<el-input v-model="dialogData.FormData.content" type="textarea" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="onSubmit()">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import {
Search,
Edit,
Delete,
UserFilled,
InfoFilled,
View,
} from '@element-plus/icons-vue'
import {
getUserList,
addUserList,
listUpdate,
} from '../../../api/modules/index.js'
import { options } from './options.js'
import { onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getDateTime } from '../../../utils/index.js'
const queryData = ref({
keyWord: '',
page: 1,
size: 10,
})
const FormRef = ref()
const formLabelWidth = '140px'
const dialogData = reactive({
isView: true,
title: '添加',
FormData: {
username: '',
email: '',
address: '',
content: '',
},
})
const dialogWidth = ref('0')
const rules = reactive({
username: [{ required: true, message: '请填写用户姓名', trigger: 'change' }],
email: [{ required: true, message: '请填写邮箱', trigger: 'change' }],
address: [{ required: true, message: '请填写居住地址', trigger: 'change' }],
content: [{ required: true, message: '请填写备注信息', trigger: 'change' }],
})
const oldTableData = ref([])
const dialogVisible = ref(false)
const tableData = ref([])
const total = ref(0)
const initData = () => {
getUserList(queryData.value).then((res) => {
total.value = res.data.data.total
tableData.value = res.data.data.userList
})
}
const dialogVisibleShow = () => {
dialogData.FormData = {
username: '',
email: '',
address: '',
content: '',
}
dialogVisible.value = true
}
const onSubmit = () => {
FormRef.value.validate(async (valid) => {
if (!valid) return
try {
if (dialogData.FormData.id) {
listUpdate(dialogData.FormData).then((res) => {
console.log('编辑数据成功')
console.log(ElMessage)
ElMessage({
message: '编辑用户成功',
type: 'success',
})
tableData.value = res.data.data
})
} else {
dialogData.FormData.date = getDateTime('')
addUserList(dialogData.FormData)
.then((res) => {
ElMessage({
message: '添加用户成功',
type: 'success',
})
dialogData.FormData.id = res.data.data.id
tableData.value.unshift(dialogData.FormData)
})
.catch((err) => {})
}
dialogVisible.value = false
} catch (error) {
console.log(error)
}
})
}
const handleCurrentChange = (val) => {
queryData.value.page = val
initData(queryData.value)
}
const editorClick = (item) => {
dialogVisible.value = true
dialogData.FormData = item
console.log(dialogData.FormData)
dialogData.isView = false
dialogData.title = '编辑'
}
const ItemView = (item) => {
dialogVisible.value = true
dialogData.FormData = item
dialogData.isView = false
dialogData.title = ''
}
const DeleteItem = (index) => {
console.log(index)
tableData.value.splice(index, 1)
}
const cancelEvent = () => {
console.log('cancel!')
}
const setDialogWidth = () => {
console.log(document.body.clientWidth)
var val = document.body.clientWidth
const def = 800 // 默认宽度
if (val < def) {
dialogWidth.value = '100%'
} else {
dialogWidth.value = def + 'px'
}
}
onMounted(() => {
setDialogWidth()
window.onresize = () => {
return (() => {
setDialogWidth()
})()
}
initData()
})
</script>
<style lang="scss" scoped>
.henader-card {
margin-bottom: 20px;
}
.icon-view {
font-size: 20px;
color: #673ab7;
margin: 0 10px;
}
.icon-edit {
font-size: 20px;
color: #2f60c2;
margin: 0 10px;
}
.icon-dele {
font-size: 20px;
color: #ff5722;
}
.mt-4 {
float: right;
text-align: right;
margin-top: 20px;
margin-bottom: 20px;
}
.el-button--text {
margin-right: 15px;
}
.el-select {
width: 300px;
}
.el-input {
width: 300px;
}
.dialog-footer button:first-child {
margin-right: 10px;
}
</style>
+39
View File
@@ -0,0 +1,39 @@
export const options = [{
label: '用户名',
props: 'username',
width: 'auto',
align: 'left'
},
{
label: '邮箱',
props: 'email',
width: 'auto',
align: 'left'
},
{
label: '创建时间',
props: 'date',
width: 'auto',
align: 'left'
},
{
label: '地址',
props: 'address',
width: 'auto',
align: 'left'
},
{
label: '备注',
props: 'content',
width: 'auto',
align: 'left',
show: true
},
{
label: '操作',
props: 'actions',
width: '150',
align: 'center',
fixed: 'right',
}
]
+34
View File
@@ -0,0 +1,34 @@
<template>
<el-card>
<el-button type="primary" @click="importExcel">导入Excel</el-button>
</el-card>
<filesUpload ref="importRef" @gatewayData="gatewayData"></filesUpload>
<el-card class="mt10">
<el-table :data="tableData" border size="small"></el-table>
</el-card>
</template>
<script setup>
import { ref } from 'vue'
// import XLSX from 'xlsx'
import filesUpload from '../../../components/filesUpload.vue'
const importRef = ref('')
const tableData = ref([])
const importExcel = () => {
let params = {}
importRef.value.acceptParams(params)
console.log(importRef.value.acceptParams(params))
}
const gatewayData = (params) => {
console.log(params)
}
</script>
<style lang="scss" scoped>
.mt-4 {
float: right;
text-align: right;
margin-bottom: 20px;
}
</style>
+248
View File
@@ -0,0 +1,248 @@
<template>
<el-card>
<el-button type="primary" class="mt-4" @click="dialogVisibleHanle"
>编辑表格</el-button
>
</el-card>
<el-card class="mt10">
<el-table
:data="tableData"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
border
stripe
style="width: 100%"
>
<el-table-column
v-for="item in columnData"
:key="item.props"
:prop="item.props"
:label="item.label"
:width="item.width"
v-show="item.show"
:fixed="item.fixed"
:align="item.align"
show-overflow-tooltip
></el-table-column>
</el-table>
<el-pagination
class="mt10 mt-4"
v-model:currentPage="queryData.page"
v-model:page-size="queryData.size"
:page-sizes="[10]"
:disabled="disabled"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
<el-dialog
v-model="dialogVisible"
title="编辑列表"
width="80%"
:before-close="handleClose"
>
<el-table
class="t1"
row-key="id"
ref="dragTable"
:data="tableDialog"
:row-class-name="tableRowClassName"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
border
stripe
style="width: 100%"
>
<el-table-column
v-for="item in DialogColumn"
:key="item.props"
:prop="item.props"
:label="item.label"
>
<template v-slot:default="scope" v-if="item.props === 'label'">
<el-input v-model.trim="scope.row.label"></el-input>
</template>
<template v-slot:default="scope" v-if="item.props === 'width'">
<el-input v-model.trim="scope.row.width"></el-input>
</template>
<template v-slot:default="scope" v-if="item.props === 'align'">
<el-select
v-model="scope.row[scope.column.property]"
placeholder="Select"
>
<el-option
v-for="i in optionsType"
:key="i.value"
:label="i.label"
:value="i.value"
/>
</el-select>
</template>
<template v-slot:default="scope" v-if="item.props === 'show'">
<el-switch v-model="scope.row.show" />
</template>
<template v-slot:default="scope" v-if="item.props === 'fiexd'">
<el-select v-model="scope.row.fixed" placeholder="Select">
<el-option
v-for="i in fiexdType"
:key="i.value"
:label="i.label"
:value="i.value"
/>
</el-select>
</template>
</el-table-column>
</el-table>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="dialogSubmit">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { nextTick, onMounted, reactive, ref } from 'vue'
import { getUserList } from '../../../api/modules/index.js'
import { options } from './options.js'
import Sortable from 'sortablejs'
const tableData = ref([])
const id = ref('')
const tableDialog = ref([])
const optionsType = ref([
{ value: 'left', label: '右对齐' },
{ value: 'right', label: '左对齐' },
{ value: 'center', label: '居中' },
])
const fiexdType = ref([
{ value: true, label: '是' },
{ value: false, label: '否' },
])
const DialogColumn = ref([
{
label: '表头',
props: 'label',
},
{
label: '对应列的宽度',
props: 'width',
},
{
label: '对齐方式',
props: 'align',
},
{
label: '是否显示',
props: 'show',
},
{
label: '列是否固定',
props: 'fiexd',
},
])
const columnData = ref(JSON.parse(JSON.stringify(options)))
const disabled = ref(false)
const dialogVisible = ref(false)
const total = ref(0)
const queryData = ref({
keyWord: '',
page: 1,
size: 10,
})
const initData = () => {
getUserList(queryData.value).then((res) => {
total.value = res.data.data.total
tableData.value = res.data.data.userList
})
}
const handleSizeChange = (val) => {
console.log(val)
}
const handleCurrentChange = (val) => {
queryData.value.page = val
initData(queryData.value)
}
const handleClose = () => {}
const dialogVisibleHanle = () => {
console.log(tableData.value)
console.log(columnData)
tableDialog.value = columnData.value
console.log(tableDialog.value)
dialogVisible.value = true
nextTick(() => {
initSortable('t1')
})
}
const dialogSubmit = () => {
console.log(tableDialog.value)
dialogVisible.value = false
console.log(columnData.value)
}
onMounted(() => {
console.log(columnData.value)
initData()
})
const initSortable = (className) => {
console.log(className)
// 获取表格row的父节点
const table = document.querySelector(
'.' + className + ' .el-table__body-wrapper tbody'
)
// 创建拖拽实例
console.log(table)
console.log(Sortable)
let dragTable = Sortable.create(table, {
animation: 150, //动画
// disabled: false, // 拖拽不可用? false 启用(刚刚渲染表格的时候起作用,后面不起作用)
// handle: ".move", //指定拖拽目标,点击此目标才可拖拽元素(此例中设置操作按钮拖拽)
// filter: ".disabled", //指定不可拖动的类名(el-table中可通过row-class-name设置行的class)
// dragClass: "dragClass", //设置拖拽样式类名
// ghostClass: "ghostClass", //设置拖拽停靠样式类名
// chosenClass: "chosenClass", //设置选中样式类名
// 开始拖动事件
onStart: () => {
console.log('开始拖动')
},
// 结束拖动事件
onEnd: ({ newIndex, oldIndex }) => {
console.log('结束拖动', `拖动前索引${oldIndex}---拖动后索引${newIndex}`)
const currRow = tableDialog.value.splice(oldIndex, 1)[0]
tableDialog.value.splice(newIndex, 0, currRow)
console.log('结束拖动', tableDialog.value)
},
})
}
function tableRowClassName({ row }) {
if (row.disabled) {
return 'disabled'
}
return ''
}
</script>
<style lang="scss" scoped>
.mt-4 {
float: right;
text-align: right;
margin-bottom: 20px;
}
.dragClass {
background: rgba($color: #41c21a, $alpha: 0.5) !important;
}
// 停靠
.ghostClass {
background: rgba($color: #6cacf5, $alpha: 0.5) !important;
}
// 选择
.chosenClass:hover > td {
background: rgba($color: #f56c6c, $alpha: 0.5) !important;
}
</style>
+41
View File
@@ -0,0 +1,41 @@
export const options = [{
label: "用户名",
props: "username",
width: "auto",
align: "left",
show: true,
fixed: false,
},
{
label: "邮箱",
props: "email",
width: "auto",
align: "left",
show: true,
fixed: false,
},
{
label: "创建时间",
props: "date",
width: "auto",
align: "left",
show: true,
fixed: false,
},
{
label: "地址",
props: "address",
width: "auto",
align: "left",
show: true,
fixed: false,
},
{
label: "备注",
props: "content",
width: "auto",
align: "left",
show: true,
fixed: false,
},
];
+175
View File
@@ -0,0 +1,175 @@
<template>
<el-card class="flx-row-right">
<!-- <el-button type="primary" v-print="'#printMe'">打印</el-button> -->
<el-button type="primary" @click="scrollHanlde">滑动加载</el-button>
<el-button type="primary" @click="isShowPagHandle">分页加载</el-button>
<el-button type="primary" @click="educeExcel">导出表格</el-button>
</el-card>
<el-card class="mt10" id="printMe">
<el-table id="mutipleTable" :data="tableData" :header-cell-style="{ backgroundColor: '#ecf5ff' }" border stripe style="width: 100%" :height="heightTbale">
<el-table-column v-for="item in columnData" :key="item.props" :sortable="item.sortable" :prop="item.props" :label="item.label" :width="item.width" :fixed="item.fixed" :align="item.align">
<template v-slot:default="scope" v-if="item.props !== 'actions'">
<el-input v-model="scope.row[item.props]" v-if="scope.row.itemEdit"></el-input>
<div v-else class="one-cut-txt">{{ scope.row[item.props] }}</div>
</template>
<template v-slot:default="scope" v-if="item.props === 'actions'">
<el-icon class="icon-edit" @click="itemEditHanld(scope.row)"><Finished v-if="scope.row.itemEdit" /><Edit v-else /></el-icon>
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消" :icon="InfoFilled" icon-color="#626AEF" title="确认删除该用户?" @confirm="DeleteItem(index)" @cancel="cancelEvent">
<template #reference>
<el-icon class="icon-dele"><Delete /></el-icon>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination v-if="isShowPag" small background layout="prev, pager, next" :total="60" class="mt-4 mt10" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
</el-card>
</template>
<script setup>
import print from "vue3-print-nb";
import * as XLSX from "xlsx";
import { Edit, Delete, InfoFilled, View } from "@element-plus/icons-vue";
import { nextTick, onMounted, reactive, ref } from "vue";
import { orderLists } from "../../../api/modules/index.js";
import { options } from "./options.js";
const tableData = ref([]);
const oldTableData = ref([]);
const tabclickIndex = ref();
const columnData = ref(JSON.parse(JSON.stringify(options)));
const disabled = ref(false);
const dialogVisible = ref(false);
const total = ref(0);
const queryData = ref({
keyWord: "",
page: 1,
size: 10,
});
const heightTbale = ref("auto");
const isShowPag = ref(true);
const scrollHanlde = () => {
heightTbale.value = "75vh";
isShowPag.value = false;
oldTableData.value = [];
queryData.value.page = 1;
queryData.value.size = 15;
initData();
// let table = mutipleTable.value._value.layout.table.refs.bodyWrapper;
let table = document.getElementById("mutipleTable");
table.addEventListener(
"scroll",
(res) => {
console.log("/监听表格滚动事件");
loadmore(res);
},
true
);
};
const isShowPagHandle = () => {
isShowPag.value = true;
heightTbale.value = "auto";
queryData.value.page = 1;
queryData.value.size = 10;
initData();
};
const cancelEvent = (val) => {
console.log("取消");
};
const initData = () => {
orderLists(queryData.value).then((res) => {
console.log(res.data.data);
// total.value = res.data.data.total
if (queryData.value.size == 10) {
tableData.value = res.data.data;
} else {
tableData.value = res.data.data.slice(queryData.value.page - 1, queryData.value.size);
oldTableData.value = res.data.data;
}
});
};
const itemEditHanld = (item) => {
item.itemEdit = !item.itemEdit;
// // console.log(JSON.stringify(item));
// tabclickIndex.value = item;
};
const handleSizeChange = (val) => {
console.log(val);
};
const handleCurrentChange = (val) => {
queryData.value.page = val;
initData(queryData.value);
};
const handleClose = () => {};
const dialogVisibleHanle = () => {
console.log("滑动加载");
};
const educeExcel = () => {
console.log("导出表格");
const data = XLSX.utils.json_to_sheet(tableData.value); //此处tableData.value为表格的数据
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, data, "test-data"); //test-data为自定义的sheet表名
XLSX.writeFile(wb, "测试.xlsx"); //test.xlsx为自定义的文件名
};
// https://www.zcool.com.cn/work/ZMzUzMDA0MDQ=.html
onMounted(() => {
console.log(columnData.value);
initData();
});
const loadmore = (res) => {
// 再距离底部20px的时候滚动加载下一条
if (res.target.scrollTop && res.target.scrollHeight - 2 <= res.target.scrollTop + res.target.clientHeight) {
console.log(queryData.value.page);
queryData.value.page++;
if (queryData.value.page > 5) return;
tableData.value = tableData.value.concat(
// res.data.data
oldTableData.value.slice(queryData.value.size * queryData.value.page - queryData.value.size, queryData.value.size * queryData.value.page)
);
}
};
const vPrint = (event) => {
event.print;
};
</script>
<style lang="scss" scoped>
.mt-4 {
float: right;
text-align: right;
margin-bottom: 20px;
}
.dragClass {
background: rgba($color: #41c21a, $alpha: 0.5) !important;
}
// 停靠
.ghostClass {
background: rgba($color: #6cacf5, $alpha: 0.5) !important;
}
// 选择
.chosenClass:hover > td {
background: rgba($color: #f56c6c, $alpha: 0.5) !important;
}
.icon-view {
font-size: 20px;
color: #673ab7;
margin: 0 10px;
}
.icon-edit {
font-size: 20px;
color: #2f60c2;
margin: 0 10px;
}
.icon-dele {
font-size: 20px;
color: #ff5722;
}
</style>
+122
View File
@@ -0,0 +1,122 @@
export const options = [
{
label: "序号",
props: "goodsId",
width: "60",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "机构代码",
props: "code",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "机构名",
props: "title",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "商品名称",
props: "goodsname",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "商品条码",
props: "commodity",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "规格",
props: "sku",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "品牌",
props: "brand",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "销售数量",
props: "number",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: true,
},
{
label: "剩余库存",
props: "inventory",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: true,
},
{
label: "成本价",
props: "costPrice",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: true,
},
{
label: "成本金额",
props: "amount",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: true,
},
{
label: "操作",
props: "actions",
width: "auto",
align: "left",
show: true,
fixed: "right",
itemEdit: "itemEdit",
sortable: false,
},
];
+208
View File
@@ -0,0 +1,208 @@
<template>
<el-card>
<div class="mt-4">
<el-button type="primary" @click="handleExpand">折叠全部</el-button>
<el-button type="primary" @click="handleOpen">展开全部</el-button>
</div>
</el-card>
<el-card class="mt10">
<el-table
ref="table"
:data="tableData"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
border
stripe
style="width: 100%"
>
<el-table-column type="expand">
<template #default="props">
<div class="m10">
<div class="expand-title">机构信息</div>
<el-table
:header-cell-style="{ backgroundColor: '#FAFAFA' }"
:data="props.row.ItemData"
border
style="border-bottom: none"
>
<el-table-column
v-for="ctx in ItemData"
:key="ctx.props"
:sortable="ctx.sortable"
:prop="ctx.props"
:label="ctx.label"
:width="ctx.width"
:fixed="ctx.fixed"
:align="ctx.align"
show-overflow-tooltip
>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column
v-for="item in columnData"
:key="item.props"
:sortable="item.sortable"
:prop="item.props"
:label="item.label"
:width="item.width"
:fixed="item.fixed"
:align="item.align"
show-overflow-tooltip
>
<template v-slot:default="scope" v-if="item.props !== 'actions'">
<el-input
v-model="scope.row[item.props]"
v-if="scope.row.itemEdit"
></el-input>
<div v-else class="one-cut-txt">{{ scope.row[item.props] }}</div>
</template>
<template v-slot:default="scope" v-if="item.props === 'actions'">
<el-icon class="icon-edit" @click="itemEditHanld(scope.row)"
><Finished v-if="scope.row.itemEdit" /><Edit v-else
/></el-icon>
<el-popconfirm
confirm-button-text="确认"
cancel-button-text="取消"
:icon="InfoFilled"
icon-color="#626AEF"
title="确认删除该数据?"
@confirm="DeleteItem(index)"
>
<template #reference>
<el-icon class="icon-dele"><Delete /></el-icon>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
small
background
layout="prev, pager, next"
:total="50"
class="mt-4 mt10"
@current-change="handleCurrentChange"
/>
</el-card>
</template>
<script setup>
import * as XLSX from 'xlsx'
import {
Edit,
Delete,
InfoFilled,
View,
ArrowDownBold,
Plus,
} from '@element-plus/icons-vue'
import { nextTick, onMounted, reactive, ref } from 'vue'
import { orderLists } from '../../../api/modules/index.js'
import { options, ItemData } from './options.js'
const tableData = ref([])
const table = ref()
const tabclickIndex = ref()
const isExpand = ref(false)
const columnData = ref(JSON.parse(JSON.stringify(options)))
const disabled = ref(false)
const dialogVisible = ref(false)
const total = ref(0)
const formInline = ref({})
const queryData = ref({
keyWord: '',
page: 1,
size: 10,
})
const initData = () => {
orderLists(queryData.value).then((res) => {
console.log(res.data.data)
// total.value = res.data.data.total
tableData.value = res.data.data
})
}
const itemEditHanld = (item) => {
item.itemEdit = !item.itemEdit
// // console.log(JSON.stringify(item));
// tabclickIndex.value = item;
}
const handleSizeChange = (val) => {
console.log(val)
}
const handleSelectionChange = (val) => {}
const handleCurrentChange = (val) => {
queryData.value.size = 10
queryData.value.page = val
initData(queryData.value)
}
const handleClose = () => {}
const dialogVisibleHanle = () => {
console.log('滑动加载')
}
const handleExpand = () => {
isExpand.value = false
tableData.value.forEach((item) => {
table.value.toggleRowExpansion(item, isExpand.value)
})
}
const handleOpen = () => {
isExpand.value = true
tableData.value.forEach((item) => {
table.value.toggleRowExpansion(item, isExpand.value)
})
}
// https://www.zcool.com.cn/work/ZMzUzMDA0MDQ=.html
onMounted(() => {
console.log(columnData.value)
initData()
})
</script>
<style lang="scss" scoped>
.mt-4 {
float: right;
text-align: right;
margin-bottom: 20px;
}
.demo-form-inline {
}
.dragClass {
background: rgba($color: #41c21a, $alpha: 0.5) !important;
}
// 停靠
.ghostClass {
background: rgba($color: #6cacf5, $alpha: 0.5) !important;
}
// 选择
.chosenClass:hover > td {
background: rgba($color: #f56c6c, $alpha: 0.5) !important;
}
.icon-view {
font-size: 20px;
color: #673ab7;
margin: 0 10px;
}
.icon-edit {
font-size: 20px;
color: #2f60c2;
margin: 0 10px;
}
.icon-dele {
font-size: 20px;
color: #ff5722;
}
.btn-color {
background: #fff;
color: #4c60cc;
}
.expand-title {
padding: 10px;
color: #919399;
font-weight: 600;
}
</style>
+163
View File
@@ -0,0 +1,163 @@
export const options = [{
label: "序号",
props: "goodsId",
width: "60",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "机构代码",
props: "code",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "机构名",
props: "title",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "商品名称",
props: "goodsname",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "商品条码",
props: "commodity",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "规格",
props: "sku",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "品牌",
props: "brand",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "销售数量",
props: "number",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: true,
},
{
label: "剩余库存",
props: "inventory",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: true,
},
{
label: "成本价",
props: "costPrice",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: true,
},
{
label: "成本金额",
props: "amount",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: true,
},
{
label: "操作",
props: "actions",
width: "auto",
align: "left",
show: true,
fixed: "right",
itemEdit: "itemEdit",
sortable: false,
},
];
export const ItemData = [{
label: "地址信息",
props: "address",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "联系方式",
props: "email",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "营业状态",
props: "state",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
{
label: "销售额",
props: "salenumber",
width: "auto",
align: "left",
show: true,
fixed: false,
itemEdit: "itemEdit",
sortable: false,
},
];
-442
View File
@@ -1,442 +0,0 @@
<template>
<el-card class="mt10">
<el-button type="success" @click="drawer = true">
<el-icon style="margin-right: 10px;"><CirclePlus /></el-icon>
创建活动
</el-button>
<!-- <el-form :inline="true" :model="formSearch" class="mt10">-->
<!-- <el-form-item label="活动名称">-->
<!-- <el-input-->
<!-- v-model="formSearch.name"-->
<!-- style="max-width: 300px"-->
<!-- placeholder="模糊查询活动名称"-->
<!-- class="input-with-select"-->
<!-- >-->
<!-- </el-input>-->
<!-- </el-form-item>-->
<!-- <el-form-item>-->
<!-- <el-button type="primary" @click="onSearchSubmit">搜索</el-button>-->
<!-- </el-form-item>-->
<!-- </el-form>-->
<el-drawer v-model="drawer" :direction="direction" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :show-close="false">
<template #header>
<h4>创建活动</h4>
</template>
<template #default>
<el-form
:model="formData"
label-width="auto" v-loading="loading">
<el-form-item label="活动名称">
<el-input
v-model="formData.title"
placeholder="请输入活动名称"
/>
</el-form-item>
<el-form-item label="轮播图">
<el-upload
v-model:file-list="fileBannerList"
list-type="picture-card"
:before-upload="beforeUpload"
:http-request="addUploadBannerFile"
:limit="1"
:on-exceed="handleBannerExceed"
:on-remove="handleBannerRemove"
>
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item label="详情图">
<el-upload
v-model:file-list="fileDetailList"
list-type="picture-card"
:before-upload="beforeUpload"
:http-request="addUploadDetailFile"
:limit="1"
:on-exceed="handleDetailExceed"
:on-remove="handleDetailRemove"
>
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-form>
<div style="display: flex;justify-content: flex-end;margin-top: 50px">
<el-button @click="cancelClick">取消</el-button>
<el-button type="primary" @click="confirmClick">确认</el-button>
</div>
</template>
</el-drawer>
<el-table
ref="table"
:data="tableData"
:default-sort="{ prop: 'date', order: 'descending' }"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
border
stripe
class="mt10"
>
<el-table-column
label="序号"
prop="id"
width="120"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column
label="活动名称"
prop="title"
width="600"
align="left"
show-overflow-tooltip
/>
<el-table-column label="展示图" width="300px" align="center">
<template #default="scope">
<el-image style="width: 200px; height: 50px" :src="scope.row.thumbnail" lazy />
</template>
</el-table-column>
<el-table-column label="详情图" width="300px" align="center">
<template #default="scope">
<el-image style="width: 300px; height: 200px" :src="scope.row.detailImg" lazy />
</template>
</el-table-column>
<el-table-column
label="发布时间"
prop="createdAt"
width="auto"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column label="操作" width="200px" align="center">
<template v-slot:default="scope">
<el-popconfirm title="确认删除这张图片吗?" @confirm="deleteData(scope.row)">
<template #reference>
<el-button type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
size="small"
background
layout="prev, pager, next"
:total="tableData.length"
class="mt-4 mt10"
@current-change="handleCurrentChange"
/>
</el-card>
</template>
<script setup>
import {
Edit,
Delete,
InfoFilled,
View,
ArrowDownBold,
Plus, CirclePlus,
} from '@element-plus/icons-vue'
import {nextTick, onMounted, reactive, ref} from 'vue'
import {ElMessage} from "element-plus";
import {addFile} from "../../api/modules/upload";
import {getConfigList, updateSystem} from "../../api/modules/system";
const direction = ref('rtl');
const tableData = ref([])
const dataList = ref([])
const table = ref()
const isExpand = ref(false)
const dialogVisible = ref(false)
const total = ref(0)
const fileBannerList = ref([]);
const fileDetailList = ref([]);
const loading = ref(false)
const searchName = ref('');
const drawer = ref(false)
const queryData = ref({
keyWord: '',
page: 1,
size: 10,
})
const formSearch = ref({
searchName:'',
});
const formData = ref({
id: 1,
title: '',
thumbnail:'',
detailImg: '',
createdAt: '',
});
// 初始化数据
const initData = () => {
getConfigList(queryData.value).then((res) => {
if(res.data[1].content !== '[]' && res.data[1].content !== null && res.data[0].content !== "")
{
tableData.value = JSON.parse(res.data[1].content);
// 找出最ID
const id = Math.max.apply(null, tableData.value.map(item => item.id));
formData.value.id = id+1;
}
})
}
// 删除数据
const deleteData = (row) => {
// 过滤掉需要删除的项
tableData.value = tableData.value.filter(item => item.id !== row.id);
let params = {
id: 2,
content: JSON.stringify(tableData.value)
};
// 更新系统配置
updateSystem(params).then((res) => {
initData();
// 显示删除成功的消息
ElMessage({
message: '删除成功',
type: 'success'
});
});
}
// 提交表单
const confirmClick = () => {
// 检查表单数据完整性
if (!formData.value.title) {
ElMessage.error('请添加活动名称');
return;
}
if (!formData.value.thumbnail) {
ElMessage.error('请上传轮播图片');
return;
}
if (!formData.value.detailImg) {
ElMessage.error('请上传详情图片');
return;
}
formData.value.createdAt = formatDate(); // 创建时间
// 合并旧数据,写入新数据
let newData = tableData.value.concat([formData.value]);
let params = {
id: 2,
content: JSON.stringify(newData)
};
// 更新系统配置
updateSystem(params).then((res) => {
drawer.value = false;
formData.value = {
id: 1,
title: '',
thumbnail:'',
detailImg: '',
createdAt: ''
}
fileBannerList.value = [];
fileDetailList.value = [];
initData();
ElMessage({
message: '添加成功',
type: 'success',
})
});
}
// 创建格式化日期的函数
const formatDate = () => {
const date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// 取消事件
const cancelClick = () => {
drawer.value = false;
loading.value = false;
formData.value = {
id: formData.value.id,
title: '',
thumbnail:'',
detailImg: ''
}
fileBannerList.value = [];
fileDetailList.value = [];
}
// 图片上传前检测
const beforeUpload = (file) => {
loading.value = true;
const maxSize = 5 * 1024 * 1024; // 最大 2MB
if (file.size > maxSize) {
alert('文件大小不能超过 5MB');
loading.value = false;
return false;
}
const allowedTypes = ['image/jpeg', 'image/png'];
if (!allowedTypes.includes(file.type)) {
alert('只允许上传 JPEG 或 PNG 图片');
loading.value = false;
return false;
}
return true;
}
// 轮播图图片上传限制
const handleBannerExceed= (files, uploadFiles) => {
ElMessage.warning(
`轮播图最多可上传1张`
)
}
// 详情图片上传限制
const handleDetailExceed= (files, uploadFiles) => {
ElMessage.warning(
`详情图最多可上传1张`
)
}
// 轮播图移除
const handleBannerRemove = (file, fileList) => {
formData.value.thumbnail = '';
}
// 详情图移除
const handleDetailRemove = (file, fileList) => {
formData.value.detailImg = '';
}
// 轮播图上传
const addUploadBannerFile = (params) => {
const formData = new FormData();
formData.append('files', params.file);
addFile(formData)
.then((response) => {
handleBannerSuccess(response, params.file, params.fileList);
})
.catch((error) => {
if(!error)
{
handleError(error, params.file, params.fileList);
}
});
}
// 详情图上传
const addUploadDetailFile = (params) => {
const formData = new FormData();
formData.append('files', params.file);
addFile(formData)
.then((response) => {
handleDetailSuccess(response, params.file, params.fileList);
})
.catch((error) => {
if(!error)
{
handleError(error, params.file, params.fileList);
}
});
}
// 处理轮播上传成功的回调
const handleBannerSuccess = (response) => {
formData.value.thumbnail = response.data[0];
loading.value = false;
}
// 处理详情上传成功的回调
const handleDetailSuccess = (response) => {
formData.value.detailImg = response.data[0];
loading.value = false;
}
// 处理上传失败的回调
const handleError = (error, file, fileList) => {
loading.value = false;
console.error('上传失败:', error, file, fileList);
}
const handleCurrentChange = (val) => {
queryData.value.size = 10
queryData.value.page = val
initData(queryData.value)
}
// 搜索事件
const onSearchSubmit = ()=> {
console.log('点击搜索');
};
onMounted(() => {
initData()
})
</script>
<style lang="scss" scoped>
</style>
-75
View File
@@ -1,75 +0,0 @@
<template>
<el-card>
<el-form :model="form" label-width="auto" style="max-width: 600px;">
<el-form-item label="客服电话">
<span>{{ serviceTelephone }}</span>
</el-form-item>
<el-form-item label="修改电话">
<el-input v-model="form.content" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">修改</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script setup>
import {onMounted, reactive, ref} from 'vue'
import {getConfigList, updateConfig} from "../../api/modules/system";
import {ElMessage} from "element-plus";
// do not use same name with ref
const form = reactive({
id: undefined,
content: ''
})
let serviceTelephone = ref("400 000 0000")
const initData = () => {
getConfigList().then((res) => {
console.log(res.data);
if (Array.isArray(res.data) && res.data.length > 0) {
let customerServicePhoneRecord = res.data.find(item => item.title === "客服电话");
if (customerServicePhoneRecord) {
// 如果找到了匹配的记录,你可以根据需要进行处理
console.log("找到客服电话记录:", customerServicePhoneRecord);
// 如果需要,可以将这条记录赋值给某个变量或用于其他操作
form.id = customerServicePhoneRecord.id;
form.content = customerServicePhoneRecord.content;
serviceTelephone.value = customerServicePhoneRecord.content;
} else {
console.log("未找到客服电话记录");
}
} else {
console.log("res.data 是空或不是一个数组");
}
}).catch((error) => {
console.error("获取配置列表时出错:", error);
});
}
const onSubmit = () => {
console.log('submit!')
updateConfig(form).then((res) => {
serviceTelephone.value = form.content;
console.log('编辑数据成功')
console.log(ElMessage)
ElMessage({
message: '编辑服务项目成功',
type: 'success',
})
// tableData.value = res.data
})
}
onMounted(() => {
initData()
})
</script>
<style lang="scss" scoped></style>
-79
View File
@@ -1,79 +0,0 @@
<template>
<el-card>
<el-form :model="formData" label-width="auto" style="max-width: 600px;">
<el-form-item label="账号">
<span>admin</span>
</el-form-item>
<el-form-item
:rules="[
{ required: true, message: '请输入密码' },
]"
label="旧密码">
<el-input
v-model="formData.oldPassword"
style="width: 240px"
type="password"
placeholder="请输入密码"
show-password
/>
</el-form-item>
<!-- <el-alert type="info" show-icon :closable="false" style="margin-bottom: 10px">-->
<!-- <p>留空则不修改账号名,如果账号修改后,旧账号将不能用!</p>-->
<!-- </el-alert>-->
<!-- <el-form-item label="修改账号">-->
<!-- <el-input v-model="form.name" />-->
<!-- </el-form-item>-->
<el-alert type="info" show-icon :closable="false" style="margin-bottom: 10px">
<p>留空则不修改密码,如果密码修改后,旧密码将不能用!</p>
</el-alert>
<el-form-item label="新密码">
<el-input
v-model="formData.newPassword"
style="width: 240px"
type="password"
placeholder="请输入新密码"
show-password
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">修改</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script setup>
import { reactive } from 'vue'
import {updateAdmin} from "../../api/modules/config";
import {ElMessage} from "element-plus";
import {useRouter} from "vue-router";
const router = useRouter();
const formData = reactive({
oldPassword: '',
newPassword: '',
})
const onSubmit = () => {
// 修改密码
updateAdmin(formData).then(res => {
ElMessage({
message: '修改成功,请重新登录',
type: 'success',
});
sessionStorage.removeItem("token");
router.push("/login");
});
}
</script>
<style lang="scss" scoped></style>
-346
View File
@@ -1,346 +0,0 @@
<template>
<el-card class="mt10">
<el-button type="success" @click="drawer = true">
上传首页图
<el-icon class="el-icon--right">
<Upload/>
</el-icon>
</el-button>
<el-drawer v-model="drawer" :direction="direction" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :show-close="false">
<template #header>
<h4>上传图片</h4>
</template>
<template #default>
<el-form
:model="formData"
label-width="auto" v-loading="loading">
<el-form-item label="序号">
<el-input
v-model="formData.sort"
type="number"
placeholder="请输入图片排序"
disabled
/>
</el-form-item>
<el-form-item label="首页图">
<el-upload
v-model:file-list="fileList"
list-type="picture-card"
:before-upload="beforeUpload"
:http-request="addUploadDetailFile"
:limit="1"
:on-exceed="handleDetailExceed"
:on-remove="handleDetailRemove"
>
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-form>
<div style="display: flex;justify-content: flex-end;margin-top: 50px">
<el-button @click="cancelClick">取消</el-button>
<el-button type="primary" @click="confirmClick">确认</el-button>
</div>
</template>
</el-drawer>
<el-table
ref="table"
:data="tableData"
:default-sort="{ prop: 'date', order: 'descending' }"
:header-cell-style="{ backgroundColor: '#ecf5ff' }"
border
stripe
class="mt10"
v-loading="loading"
>
<el-table-column
label="序号"
prop="sort"
width="120"
align="center"
show-overflow-tooltip
sortable
/>
<el-table-column label="首页图" align="center">
<template #default="scope">
<el-image style="width: 300px; height: 200px" :src="scope.row.img" lazy/>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template v-slot:default="scope">
<el-popconfirm title="确认删除这张图片吗?" @confirm="deleteData(scope.row)">
<template #reference>
<el-button type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
<script setup>
import * as XLSX from 'xlsx'
import {
Edit,
Delete,
InfoFilled,
View,
ArrowDownBold,
Plus,
} from '@element-plus/icons-vue'
import {nextTick, onMounted, reactive, ref} from 'vue'
import {options} from './options.js'
import {getConfigList, updateSystem} from "../../api/modules/system";
import {addFile} from "../../api/modules/upload";
import {ElMessage} from "element-plus";
const tableData = ref([])
const table = ref()
const dialogVisible = ref(false)
const total = ref(0)
const direction = ref('rtl');
const drawer = ref(false)
const queryData = ref({
keyWord: '',
page: 1,
size: 10,
})
const fileList = ref([]);
const loading = ref(false)
const formData = ref({
sort: 1,
img: ''
});
// 初始化数据
const initData = () => {
getConfigList(queryData.value).then((res) => {
if(res.data[0].content !== '[]' && res.data[0].content !== null && res.data[0].content !== "")
{
tableData.value = JSON.parse(res.data[0].content);
// 找出最大序号
const sort = Math.max.apply(null, tableData.value.map(item => item.sort));
formData.value.sort = sort+1;
}
loading.value = false;
})
}
// 提交表单
const confirmClick = () => {
// 检查表单数据完整性
if (!formData.value.img) {
ElMessage.error('请上传图片');
return;
}
// 合并旧数据,写入新数据
let newData = tableData.value.concat([formData.value]);
let params = {
id: 1,
content: JSON.stringify(newData)
};
// 更新系统配置
updateSystem(params).then((res) => {
drawer.value = false;
fileList.value = [];
formData.value = {
sort: 1,
img: ''
}
initData();
ElMessage({
message: '添加成功',
type: 'success',
})
});
}
// 取消
const cancelClick = () => {
drawer.value = false;
loading.value = false;
formData.value = {
sort: formData.value.sort,
img: ''
}
fileList.value = [];
}
// 移除数据
const deleteData = (row) => {
// 过滤掉需要删除的项
tableData.value = tableData.value.filter(item => item.sort !== row.sort);
let params = {
id: 1,
content: JSON.stringify(tableData.value)
};
// 更新系统配置
updateSystem(params).then((res) => {
// 显示删除成功的消息
ElMessage({
message: '删除成功',
type: 'success'
});
initData();
});
}
// 上传前的钩子
const beforeUpload = (file) => {
loading.value = true;
const maxSize = 5 * 1024 * 1024; // 最大 2MB
if (file.size > maxSize) {
alert('文件大小不能超过 5MB');
loading.value = false;
return false;
}
const allowedTypes = ['image/jpeg', 'image/png'];
if (!allowedTypes.includes(file.type)) {
alert('只允许上传 JPEG 或 PNG 图片');
loading.value = false;
return false;
}
return true;
}
// 详情图片上传限制
const handleDetailExceed= (files, uploadFiles) => {
ElMessage.warning(
`详情图最多可上传1张`
)
}
// 详情图移除
const handleDetailRemove = (file, fileList) => {
formData.value.img = '';
}
// 详情上传
const addUploadDetailFile = (params) => {
const formData = new FormData();
formData.append('files', params.file);
addFile(formData)
.then((response) => {
handleDetailSuccess(response, params.file, params.fileList);
})
.catch((error) => {
if(error)
{
handleError(error, params.file, params.fileList);
}
});
}
// 处理详情上传成功的回调
const handleDetailSuccess = (response) => {
formData.value.img = response.data[0];
loading.value = false;
}
// 处理上传失败的回调
const handleError = (error, file, fileList) => {
loading.value = false;
console.error('上传失败:', error, file, fileList);
}
onMounted(() => {
loading.value = true;
initData()
})
</script>
<style lang="scss" scoped>
.mt-4 {
float: right;
text-align: right;
margin-bottom: 20px;
}
.demo-form-inline {
}
.dragClass {
background: rgba($color: #41c21a, $alpha: 0.5) !important;
}
// 停靠
.ghostClass {
background: rgba($color: #6cacf5, $alpha: 0.5) !important;
}
// 选择
.chosenClass:hover > td {
background: rgba($color: #f56c6c, $alpha: 0.5) !important;
}
.icon-view {
font-size: 20px;
color: #673ab7;
margin: 0 10px;
}
.icon-edit {
font-size: 20px;
color: #2f60c2;
margin: 0 10px;
}
.icon-dele {
font-size: 20px;
color: #ff5722;
}
.btn-color {
background: #fff;
color: #4c60cc;
}
.expand-title {
padding: 10px;
color: #919399;
font-weight: 600;
}
</style>
+7
View File
@@ -0,0 +1,7 @@
<template>
<div>roles</div>
</template>
<script setup></script>
<style lang="scss" scoped></style>
-86
View File
@@ -1,86 +0,0 @@
export const options = [
{
userId: 1,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '高永建',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},
{
userId: 2,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '张三',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-10 10:11:01'
},
{
userId: 3,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '李四',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-13 10:11:01'
},
{
userId: 4,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-02 10:11:01'
},{
userId: 5,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-01 10:11:01'
},
{
userId: 6,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},{
userId: 7,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},{
userId: 8,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},{
userId: 9,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},{
userId: 10,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},
{
userId: 11,
avatar: 'https://pic.qqans.com/up/2024-6/2024620113729773.jpg',
name: '名称',
nickname: '软件开发老高',
mobile: '19136448763',
date: '2024-10-11 10:11:01'
},
];

Some files were not shown because too many files have changed in this diff Show More