diff --git a/src/api/myAxios.ts b/src/api/myAxios.ts index 5cb4688..0a72ae1 100644 --- a/src/api/myAxios.ts +++ b/src/api/myAxios.ts @@ -4,8 +4,8 @@ import router from '../router' const myAxios = axios.create({ withCredentials:true, - // baseURL: 'http://localhost:9092/api' - baseURL: 'http://123.249.108.160:8888/api' //测试服务器 + baseURL: 'http://localhost:9092/api' + // baseURL: 'http://123.249.108.160:8888/api' //测试服务器 // baseURL: 'http://154.8.193.216:9092/api', //隋雨霏服务器 // baseURL: 'http://154.8.193.216:9093/api' //隋雨霏服务器测试环境 }); diff --git a/src/img/dashBoard/3.1拍摄.png b/src/img/dashBoard/3.1拍摄.png new file mode 100644 index 0000000..69f75c4 Binary files /dev/null and b/src/img/dashBoard/3.1拍摄.png differ diff --git a/src/img/dashBoard/product.png b/src/img/dashBoard/product.png new file mode 100644 index 0000000..ea52978 Binary files /dev/null and b/src/img/dashBoard/product.png differ diff --git a/src/img/dashBoard/课程表.png b/src/img/dashBoard/课程表.png new file mode 100644 index 0000000..41caa2a Binary files /dev/null and b/src/img/dashBoard/课程表.png differ diff --git a/src/layout/components/Aside.vue b/src/layout/components/Aside.vue index f08a4f3..06f2856 100644 --- a/src/layout/components/Aside.vue +++ b/src/layout/components/Aside.vue @@ -65,7 +65,7 @@ </el-aside> </template> -<script setup > +<script setup> import {ref ,computed } from 'vue' import { defineProps } from 'vue'; import emitter from '@/utils/emitter' @@ -91,7 +91,8 @@ import { Discount, Notification, Tickets, - Money + Money, + Odometer } from "@element-plus/icons-vue"; defineProps(['send-data']) @@ -120,7 +121,7 @@ emitter.on('Aside', (value) => { //动态路由导航 const router = useRouter() -console.log('router--->',router.options.routes); +// console.log('router--->',router.options.routes); // 创建图标映射表 const iconComponents = { @@ -144,7 +145,8 @@ const iconComponents = { Discount, Notification, Tickets, - Money + Money, + Odometer // 添加其他图标组件映射 }; // 过滤掉不需要展示的路由,并调整 layout 的子路由 @@ -168,10 +170,10 @@ const menuRoutes = computed(() => { } return route; }); - console.log('adj--->',adjustedRoutes); + // console.log('adj--->',adjustedRoutes); return adjustedRoutes; }); -console.log('menuRoutes--->',menuRoutes.value); +// console.log('menuRoutes--->',menuRoutes.value); </script> <style scoped> diff --git a/src/layout/components/calendarUtil.vue b/src/layout/components/calendarUtil.vue index 83fde54..903df58 100644 --- a/src/layout/components/calendarUtil.vue +++ b/src/layout/components/calendarUtil.vue @@ -146,6 +146,7 @@ const subList =(index: number)=>{ } } const saveTime =(index : number)=>{ //将开始时间和结束时间格式化存入periodObj中 + try{ periodObj.value.timePeriodAddRequestList[index].timeSlot = timePickArr.value[index][0]+'-'+timePickArr.value[index][1] } catch { diff --git a/src/layout/components/richTextUtil.vue b/src/layout/components/richTextUtil.vue new file mode 100644 index 0000000..13ceb46 --- /dev/null +++ b/src/layout/components/richTextUtil.vue @@ -0,0 +1,57 @@ +<template> + <div style="border: 1px solid #ccc"> + <Toolbar style="border-bottom: 1px solid #ccc; width: 400px;" :editor="editorRef" :defaultConfig="toolbarConfig" + :mode="mode" /> + <Editor style="height: 500px; overflow-y: hidden; width: 400px;" v-model="context" :defaultConfig="editorConfig" + :mode="mode" @onChange="handleChange" @onCreated="handleCreated" /> + </div> +</template> + +<script setup> +import '@wangeditor/editor/dist/css/style.css' // 引入 css +import { onBeforeUnmount, ref, shallowRef, onMounted, defineEmits, toRefs } from 'vue' +import { Editor, Toolbar } from '@wangeditor/editor-for-vue' +// 编辑器实例,必须用 shallowRef +const editorRef = shallowRef() +// 内容 HTML +const valueHtml = ref('') +const emit = defineEmits(['richTextContent']) //子组件向父组件传值 +const props = defineProps({ + context: String +}) +// 模拟 ajax 异步获取内容 +onMounted(() => { + setTimeout(() => { + if(props.context != undefined) { + valueHtml.value = props.context //访问父组件的值,回显 + } + }, 1500) +}) +const toolbarConfig = {} + +const editorConfig = { + placeholder: '请输入内容...', + MENU_CONF: { + uploadImage: { + server: 'http://localhost:9092/api/file/upload/single', // 图片上传接口 + fieldName: 'file', // 上传字段名,根据自己的接口参数配置 + } + } +} +// 组件销毁时,也及时销毁编辑器 +onBeforeUnmount(() => { + const editor = editorRef.value + if (editor == null) return + editor.destroy() +}) +const handleCreated = (editor) => { + editorRef.value = editor // 记录 editor 实例,重要! +} +const handleChange = (editor) => { //当选项改变时触发emit传值 + emit('richTextContent', props.context) + // console.log('html',editor.getHtml()); +} +</script> + +<style scoped> +</style> \ No newline at end of file diff --git a/src/router/routes.ts b/src/router/routes.ts index 7f198d1..099fec8 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -1,52 +1,32 @@ -export const constantRoute = [ +export const constantRoute = [ { path: '/', - name:'login', + name: 'login', component: () => import("@/views/Login.vue"), meta: { title: '登录界面', hidden: true } }, - // 个人中心页面 + //首页 { - path: '/User', - redirect: '/PersonalCenter', - name: 'person', + path: '/HomePage', + name: '首页', + redirect: '/DashBoard', component: () => import("@/layout/Manage.vue"), meta: { - title: '用户管理', - icon: 'Menu', + title: '首页', + icon: 'House', hidden: false }, - children :[ + children: [ { - path: '/PersonalCenter', - name:'个人中心', - component: ()=> import("@/views/User/PersonalCenter.vue"), - meta: { - title: '个人中心', - icon: 'User', - hidden: false - } - }, - { - path: '/Upload', - name:'文件上传', - component: ()=> import("@/views/User/Upload.vue"), - meta: { - title: '文件上传' , - icon: 'Upload', - hidden: false - } - }, - { - path: '/UserManagement', - name:'用户列表', - component: ()=> import("@/views/User/UserManagement.vue"), - meta: { - title: '用户列表', - icon: 'Postcard', + path: '/DashBoard', + name: '仪表盘', + component: () => import("@/views/HomePage/DashBoard.vue"), + meta: { + title: '仪表盘', + icon: 'Odometer', hidden: false } } @@ -58,7 +38,7 @@ export const constantRoute = [ redirect: '/AddProduct', component: () => import("@/layout/Manage.vue"), meta: { - title : '实体类商品管理', + title: '实体类商品管理', icon: 'TakeawayBox', hidden: false }, @@ -66,8 +46,8 @@ export const constantRoute = [ { path: '/AddProduct', name: '添加商品', - component: ()=> import("@/views/Commodity/AddProduct.vue"), - meta: { + component: () => import("@/views/Commodity/AddProduct.vue"), + meta: { title: '添加商品', icon: 'Edit', hidden: false @@ -76,9 +56,9 @@ export const constantRoute = [ { path: '/MerchandiseCenter', name: '商品中心', - component: ()=> import("@/views/Commodity/MerchandiseCenter.vue"), - meta: { - title: '商品中心' , + component: () => import("@/views/Commodity/MerchandiseCenter.vue"), + meta: { + title: '商品中心', icon: 'DataAnalysis', hidden: false } @@ -86,9 +66,9 @@ export const constantRoute = [ { path: '/TypeManagement', name: '类别管理', - component: ()=> import("@/views/Commodity/TypeManagement.vue"), - meta: { - title: '类别管理' , + component: () => import("@/views/Commodity/TypeManagement.vue"), + meta: { + title: '类别管理', icon: 'Files', hidden: false } @@ -102,16 +82,16 @@ export const constantRoute = [ component: () => import("@/layout/Manage.vue"), meta: { title: '服务类商品管理', - icon : 'Calendar', + icon: 'Calendar', hidden: false }, children: [ { path: '/AddServiceProduct', name: '添加服务类商品', - component: ()=> import("@/views/ServiceType/AddServiceProduct.vue"), - meta: { - title: '添加服务类商品' , + component: () => import("@/views/ServiceType/AddServiceProduct.vue"), + meta: { + title: '添加服务类商品', icon: 'Edit', hidden: false } @@ -119,9 +99,9 @@ export const constantRoute = [ { path: '/ProductCenter', name: '服务类商品管理中心', - component: ()=> import("@/views/ServiceType/ProductCenter.vue"), - meta: { - title: '服务类商品管理中心' , + component: () => import("@/views/ServiceType/ProductCenter.vue"), + meta: { + title: '服务类商品管理中心', icon: 'DataBoard', hidden: false } @@ -142,9 +122,9 @@ export const constantRoute = [ { path: '/OrderList', name: '订单列表', - component: ()=> import("@/views/Orders/OrderList.vue"), - meta: { - title: '实体商品订单列表' , + component: () => import("@/views/Orders/OrderList.vue"), + meta: { + title: '实体商品订单列表', icon: 'Box', hidden: false } @@ -152,9 +132,9 @@ export const constantRoute = [ { path: '/ServiceOrderList', name: '服务类订单列表', - component: ()=> import("@/views/Orders/ServiceOrderList.vue"), - meta: { - title: '服务类订单列表' , + component: () => import("@/views/Orders/ServiceOrderList.vue"), + meta: { + title: '服务类订单列表', icon: 'MessageBox', hidden: false } @@ -162,9 +142,9 @@ export const constantRoute = [ { path: '/PendingServiceOrderList', name: '服务类商品待处理订单', - component: ()=> import("@/views/Orders/PendingServiceOrderList.vue"), - meta: { - title: '服务类商品待处理订单' , + component: () => import("@/views/Orders/PendingServiceOrderList.vue"), + meta: { + title: '服务类商品待处理订单', icon: 'Notification', hidden: false } @@ -184,20 +164,20 @@ export const constantRoute = [ children: [ { path: '/AddCoupons', - name:'添加优惠券', - component: ()=> import("@/views/Coupons/AddCoupons.vue"), - meta: { - title: '添加优惠券' , + name: '添加优惠券', + component: () => import("@/views/Coupons/AddCoupons.vue"), + meta: { + title: '添加优惠券', icon: 'Edit', hidden: false } }, { path: '/CouponCenter', - name:'优惠券中心', - component: ()=> import("@/views/Coupons/CouponCenter.vue"), - meta: { - title: '优惠券中心' , + name: '优惠券中心', + component: () => import("@/views/Coupons/CouponCenter.vue"), + meta: { + title: '优惠券中心', icon: 'DataAnalysis', hidden: false } @@ -218,9 +198,9 @@ export const constantRoute = [ { path: '/AddCostumes', name: '添加写真产品', - component: ()=> import("@/views/CostumeAppointments/AddCostumes.vue"), - meta: { - title: '添加写真产品' , + component: () => import("@/views/CostumeAppointments/AddCostumes.vue"), + meta: { + title: '添加写真产品', icon: 'Edit', hidden: false } @@ -228,9 +208,9 @@ export const constantRoute = [ { path: '/ClothingGrade', name: '写真产品类别', - component: ()=> import("@/views/CostumeAppointments/ClothingGrade.vue"), - meta: { - title: '写真产品类别' , + component: () => import("@/views/CostumeAppointments/ClothingGrade.vue"), + meta: { + title: '写真产品类别', icon: 'Files', hidden: false } @@ -238,9 +218,9 @@ export const constantRoute = [ { path: '/ManagementCenter', name: '写真产品中心', - component: ()=> import("@/views/CostumeAppointments/ManagementCenter.vue"), - meta: { - title: '写真产品中心' , + component: () => import("@/views/CostumeAppointments/ManagementCenter.vue"), + meta: { + title: '写真产品中心', icon: 'Tickets', hidden: false } @@ -248,9 +228,9 @@ export const constantRoute = [ { path: '/AppointmentOrder', name: '写真预约订单', - component: ()=> import("@/views/CostumeAppointments/AppointmentOrder.vue"), - meta: { - title: '写真预约订单' , + component: () => import("@/views/CostumeAppointments/AppointmentOrder.vue"), + meta: { + title: '写真预约订单', icon: 'MessageBox', hidden: false } @@ -258,9 +238,9 @@ export const constantRoute = [ { path: '/OutfitOrderDetail/:id', name: '写真预约订单详情', - component: ()=> import("@/views/CostumeAppointments/OutfitOrderDetail.vue"), - meta: { - title: '写真订单详情' , + component: () => import("@/views/CostumeAppointments/OutfitOrderDetail.vue"), + meta: { + title: '写真订单详情', hidden: true } } @@ -276,22 +256,66 @@ export const constantRoute = [ icon: 'Switch', hidden: false }, - children:[ + children: [ { path: '/refundManage', - name:'退款管理', - component: ()=> import("@/views/Refund/Refund.vue"), - meta: { - title: '退款管理' , + name: '退款管理', + component: () => import("@/views/Refund/Refund.vue"), + meta: { + title: '退款管理', icon: 'Money', hidden: false } }, ] }, + // 个人中心页面 + { + path: '/User', + redirect: '/PersonalCenter', + name: 'person', + component: () => import("@/layout/Manage.vue"), + meta: { + title: '用户管理', + icon: 'Menu', + hidden: false + }, + children: [ + { + path: '/UserManagement', + name: '用户列表', + component: () => import("@/views/User/UserManagement.vue"), + meta: { + title: '用户列表', + icon: 'Postcard', + hidden: false + } + }, + { + path: '/PersonalCenter', + name: '个人中心', + component: () => import("@/views/User/PersonalCenter.vue"), + meta: { + title: '个人中心', + icon: 'User', + hidden: false + } + }, + // { + // path: '/Upload', + // name: '文件上传', + // component: () => import("@/views/User/Upload.vue"), + // meta: { + // title: '文件上传', + // icon: 'Upload', + // hidden: false + // } + // }, + ] + }, { path: '/Test', - name:'测试页面', + name: '测试页面', component: () => import("../views/test.vue") } ] diff --git a/src/views/Commodity/MerchandiseCenter.vue b/src/views/Commodity/MerchandiseCenter.vue index 2ac390b..e785812 100644 --- a/src/views/Commodity/MerchandiseCenter.vue +++ b/src/views/Commodity/MerchandiseCenter.vue @@ -1,110 +1,118 @@ <template> <!-- 修改前请注释以前的 --> - <!-- 搜索 --> - <div> - <el-input style="width: 240px; margin-right: 10px;" suffix-icon="Search" placeholder="请输入商品名称" - v-model="productName"></el-input> - <el-button class="ml-5" type="primary" @click="onSearch(productName)" style="height: 25px; margin-right: 10px;">搜索</el-button> - <el-select v-model="editForm.type" @change="(event: any) => searchByType(event)" placeholder="商品类别" style="width: 240px; margin-right: 10px;"> - <el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value1"/> - </el-select> - <el-select v-model="state" placeholder="商品状态" @change="(event: any) => searchByState(event)" style="width: 240px; margin-right: 10px;"> - <el-option label="已上架" value="1" /> - <el-option label="已下架" value="0" /> - </el-select> - <el-button type="warning" @click="reset" style="height:25px">重置</el-button> - </div> - <div style="margin: 15px 0"> - <el-popconfirm class="ml-5" confirm-button-text='确定' cancel-button-text='取消' icon="InfoFilled" icon-color="red" - title="您确定批量删除这些数据吗?" @confirm="delBatch" width=180> - <template #reference> - <el-button style="height: 25px" class="ml-5" type="danger">批量删除 <el-icon style="margin-left: 5px;"> - <Remove /> - </el-icon></el-button> - </template> - </el-popconfirm> - </div> - <!-- 数据展示 --> - <el-table :data="tableData" border stripe header-cell-class-name="headerBg" - :cell-style="{ 'text-align': 'center', 'font-size': '16px' }" @selection-change="handleSelectionChange" @select="selectChange" - :header-cell-style="{ 'text-align': 'center' }"> - <el-table-column type="selection" width="55"></el-table-column> - <el-table-column prop="id" label="商品编号" width="80"> - <template #default="{ $index }"> - {{ $index + 1 }} - </template> - </el-table-column> - <el-table-column prop="goodImg" label="商品图片"> - <template #default="scope"> - <div> - <img :src="scope.row.goodImg.split(';')[0]" alt="" style="height: 50px;"> - </div> - </template> - </el-table-column> - <el-table-column prop="name" label="商品名称"></el-table-column> - <el-table-column prop="price" label="商品价格" width="180"> - <template #default="scope"> - <div> - {{ scope.row.price }} 元 - </div> - </template> - </el-table-column> - <el-table-column prop="type" label="商品类型"></el-table-column> - <el-table-column prop="inventory" label="商品数量"></el-table-column> - <el-table-column label="商品状态"> - <template #default="scope"> - <div> - <span style="margin-left: 10px" v-if="scope.row.isShelves == 1">上架</span> - <span style="margin-left: 10px" v-if="scope.row.isShelves == 0">下架</span> - </div> - </template> - </el-table-column> - <el-table-column label="操作" width="250px"> - <template #default="scope"> - <el-button size="small" @click="ReviseOrView(scope.$index, scope.row , 0)"> - 详情 - </el-button> - <el-button size="small" @click="ReviseOrView(scope.$index, scope.row, 1)"> - 编辑 - </el-button> - <el-button size="small" @click="handleOff(scope.$index, scope.row)"> - <div v-if="scope.row.isShelves == 1">下架 </div> - <div v-if="scope.row.isShelves == 0">上架 </div> - </el-button> - <el-popconfirm class="ml-5" confirm-button-text='确定' cancel-button-text='取消' icon="InfoFilled" icon-color="red" - title="是否确认删除" @confirm="deleteProduct(scope.row.id)" width=180> + <!-- 搜索 --> + <div> + <el-input style="width: 240px; margin-right: 10px;" suffix-icon="Search" placeholder="请输入商品名称" + v-model="productName"></el-input> + <el-button class="ml-5" type="primary" @click="onSearch(productName)" style="height: 25px; margin-right: 10px;"> + 搜索 + </el-button> + <el-select v-model="editForm.type" @change="(event: any) => searchByType(event)" placeholder="商品类别" + style="width: 240px; margin-right: 10px;"> + <el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value1"/> + </el-select> + <el-select v-model="state" placeholder="商品状态" @change="(event: any) => searchByState(event)" + style="width: 240px; margin-right: 10px;"> + <el-option label="已上架" value="1"/> + <el-option label="已下架" value="0"/> + </el-select> + <el-button type="warning" @click="reset" style="height:25px">重置</el-button> + </div> + <div style="margin: 15px 0"> + <el-popconfirm class="ml-5" confirm-button-text='确定' cancel-button-text='取消' icon="InfoFilled" icon-color="red" + title="您确定批量删除这些数据吗?" @confirm="delBatch" width=180> + <template #reference> + <el-button style="height: 25px" class="ml-5" type="danger">批量删除 + <el-icon style="margin-left: 5px;"> + <Remove/> + </el-icon> + </el-button> + </template> + </el-popconfirm> + </div> + <!-- 数据展示 --> + <el-table :data="tableData" border stripe header-cell-class-name="headerBg" + :cell-style="{ 'text-align': 'center', 'font-size': '16px' }" @selection-change="handleSelectionChange" + @select="selectChange" + :header-cell-style="{ 'text-align': 'center' }"> + <el-table-column type="selection" width="55"></el-table-column> + <el-table-column prop="id" label="商品编号" width="80"> + <template #default="{ $index }"> + {{ $index + 1 }} + </template> + </el-table-column> + <el-table-column prop="goodImg" label="商品图片"> + <template #default="scope"> + <div> + <img :src="scope.row.goodImg.split(';')[0]" alt="" style="height: 50px;"> + </div> + </template> + </el-table-column> + <el-table-column prop="name" label="商品名称"></el-table-column> + <el-table-column prop="price" label="商品价格" width="180"> + <template #default="scope"> + <div> + {{ scope.row.price }} 元 + </div> + </template> + </el-table-column> + <el-table-column prop="type" label="商品类型"></el-table-column> + <el-table-column prop="inventory" label="商品数量"></el-table-column> + <el-table-column label="商品状态"> + <template #default="scope"> + <div> + <span style="margin-left: 10px" v-if="scope.row.isShelves == 1">上架</span> + <span style="margin-left: 10px" v-if="scope.row.isShelves == 0">下架</span> + </div> + </template> + </el-table-column> + <el-table-column label="操作" width="250px"> + <template #default="scope"> + <el-button size="small" @click="ReviseOrView(scope.$index, scope.row , 0)"> + 详情 + </el-button> + <el-button size="small" @click="ReviseOrView(scope.$index, scope.row, 1)"> + 编辑 + </el-button> + <el-button size="small" @click="handleOff(scope.$index, scope.row)"> + <div v-if="scope.row.isShelves == 1">下架</div> + <div v-if="scope.row.isShelves == 0">上架</div> + </el-button> + <el-popconfirm class="ml-5" confirm-button-text='确定' cancel-button-text='取消' icon="InfoFilled" + icon-color="red" + title="是否确认删除" @confirm="deleteProduct(scope.row.id)" width=180> <template #reference> - <el-button class="ml-5" type="danger">删除</el-button> + <el-button class="ml-5" type="danger">删除</el-button> </template> </el-popconfirm> - </template> - </el-table-column> - </el-table> - <!-- 分页器 --> - <div style="padding: 10px 0"> - <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" - :current-page="searchParams.current" :page-size="searchParams.pageSize" :page-sizes="[5, 10, 15, 20]" - :small="null" :disabled="null" :background="null" layout="total, sizes, prev, pager, next, jumper" - :total="total" /> - </div> + </template> + </el-table-column> + </el-table> + <!-- 分页器 --> + <div style="padding: 10px 0"> + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" + :current-page="searchParams.current" :page-size="searchParams.pageSize" :page-sizes="[5, 10, 15, 20]" + :small="null" :disabled="null" :background="null" layout="total, sizes, prev, pager, next, jumper" + :total="total"/> + </div> <!-- 编辑/详情表单 --> <el-dialog v-model="DialogVisible" :title="title"> - <el-form label-width="100px" :disabled="disabled"> + <el-form label-width="100px" :disabled="disabled" v-model="editForm"> <el-form-item label="商品编号"> <el-input v-model="editForm.id" disabled style="width: 60px;"></el-input> </el-form-item> <el-form-item label="商品图片"> - <el-upload - v-model:file-list="ImgArr" - ref="uploadProductImg" - action="#" - list-type="picture-card" - :auto-upload="false" - multiple="true" - :on-remove="removePic" - @change="(event: any) => handleChange(event, 0)" - :on-exceed="Exceed_ProductImg" - limit="7" > + <el-upload + v-model:file-list="ImgArr" + ref="uploadProductImg" + action="#" + list-type="picture-card" + :auto-upload="false" + multiple="true" + :on-remove="removePic" + @change="(event: any) => handleChange(event, 0)" + :on-exceed="Exceed_ProductImg" + limit="7"> <el-icon> <Plus/> </el-icon> @@ -114,13 +122,13 @@ <el-input v-model="editForm.name" style="width: 200px;"></el-input> </el-form-item> <el-form-item label="产品价格" prop="price"> - <el-input-number v-model="editForm.price" min="0.01" :precision="2" :step="0.5" /> + <el-input-number v-model="editForm.price" min="0.01" :precision="2" :step="0.5"/> <p style="margin-left: 5px">元</p> </el-form-item> <div style="display: flex;"> <el-form-item label="产品类别" prop="type"> <el-select v-model="editForm.type" @change="(event: any) => loadForm(event, 1)" style="width: 120px;"> - <el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value1" /> + <el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value1"/> </el-select> </el-form-item> <!-- <el-form-item label="商品数量"> @@ -133,8 +141,8 @@ <div style="display: flex;"> <el-form-item label="是否为限定类产品" prop="festivalOrder"> <el-select v-model="editForm.festivalOrder" @change="(event: any) => loadForm(event, 0)" style="width: 70px;"> - <el-option label="是" value="1" /> - <el-option label="否" value="0" /> + <el-option label="是" value="1"/> + <el-option label="否" value="0"/> </el-select> </el-form-item> <el-form-item label="商品标签"> @@ -143,18 +151,18 @@ </div> <el-form-item label="商品图文"> <div v-if="editForm.detailImg"> - <img :src="editForm.detailImg" alt="商品图标" class="thumbnail" style="width: 100px; height: 100px;" /> + <img :src="editForm.detailImg" alt="商品图标" class="thumbnail" style="width: 100px; height: 100px;"/> </div> - <el-upload - ref="uploadProductDetail" - action="#" - list-type="picture-card" - :auto-upload="false" - multiple="true" - :on-remove="handleRemove" - @change="(event: any) => handleChange(event, 1)" - :on-exceed="Exceed_ProductDetail" - limit="1" > + <el-upload + ref="uploadProductDetail" + action="#" + list-type="picture-card" + :auto-upload="false" + multiple="true" + :on-remove="handleRemove" + @change="(event: any) => handleChange(event, 1)" + :on-exceed="Exceed_ProductDetail" + limit="1"> <el-icon> <Plus/> </el-icon> @@ -164,7 +172,7 @@ <el-input type="textarea" v-model="editForm.introDetail"></el-input> </el-form-item> </el-form> - <template #footer > + <template #footer> <span class="dialog-footer"> <el-button @click="DialogVisible = false" :disabled="disabled">取消</el-button> <el-button type="primary" @click="saveEdit" :disabled="disabled">确认</el-button> @@ -174,10 +182,17 @@ </template> <script setup lang="ts"> -import { ElMessage , type UploadProps , genFileId ,type UploadRawFile } from 'element-plus'; -import { ref, onMounted, inject } from 'vue'; +import {ElMessage, type UploadProps, genFileId, type UploadRawFile} from 'element-plus'; +import {ref, onMounted, inject} from 'vue'; import myAxios from "@/api/myAxios"; -import { handleChange, removePic, handleRemove,Exceed_ProductImg, ImgArr ,editForm} from '@/utils/entityProduct/picUpload'; +import { + handleChange, + removePic, + handleRemove, + Exceed_ProductImg, + ImgArr, + editForm +} from '@/utils/entityProduct/picUpload'; // import { handleChange, handleRemove, form, Exceed_ProductImg } from '@/utils/entityProduct/picUpload'; const total = ref(0); //总页数 const idList = ref<Number[]>([]); @@ -193,11 +208,10 @@ const title = ref('') //表单名字 const productName = ref(''); const DialogVisible = ref(false); const state = ref(''); //根据商品上架状态select栏 -const tableData : any= ref([]); //实体类商品表格 -// const editForm : any = ref({}); //编辑后的实体类商品表格 -const reload : any = inject("reload") //页面重新刷新 -const uploadProductImg : any = ref() //图片上传的ref绑定 -const uploadProductDetail : any = ref() //图片上传的ref绑定 +const tableData: any = ref([]); //实体类商品表格 +const reload: any = inject("reload") //页面重新刷新 +const uploadProductImg: any = ref() //图片上传的ref绑定 +const uploadProductDetail: any = ref() //图片上传的ref绑定 const typeList: any = ref([ { value1: '', @@ -211,8 +225,8 @@ onMounted(() => { //页面加载时获取商品列表和分类页表 }) const getProductList = async () => { try { - const res = await myAxios.post('/goods/list/page', { ...searchParams.value }); - console.log('res--->',res.data) + const res = await myAxios.post('/goods/list/page', {...searchParams.value}); + console.log('res--->', res.data) if (res.data.code === 1) { tableData.value = res.data.data.records; total.value = parseInt(res.data.data.total) //总数据量,用于分页 @@ -238,8 +252,8 @@ const getTypeList = async () => { } } const saveEdit = async () => { //编辑商品 - const res = await myAxios.post('/goods/update',{...editForm.value}) - if( res.data.code === 1 ) { + const res = await myAxios.post('/goods/update', {...editForm.value}) + if (res.data.code === 1) { ElMessage({ type: 'success', message: '更新成功' @@ -249,12 +263,12 @@ const saveEdit = async () => { //编辑商品 ElMessage.error('更新失败,请检查字段') } } -const searchByType =(event : any)=>{ //通过类别搜索 +const searchByType = (event: any) => { //通过类别搜索 searchParams.value.type = event searchParams.value.current = 1 getProductList() } -const searchByState = (event : any) => { //通过商品是否上架/下架搜索 +const searchByState = (event: any) => { //通过商品是否上架/下架搜索 searchParams.value.isShelves = event searchParams.value.current = 1 getProductList() @@ -262,7 +276,7 @@ const searchByState = (event : any) => { //通过商品是否上架/下架搜 //删除商品 const deleteProduct = async (index: number) => { console.log(typeof index) - const res = await myAxios.post('/goods/delete', { id: index }) + const res = await myAxios.post('/goods/delete', {id: index}) console.log(res) if (res.data.code === 1) { ElMessage({ @@ -274,29 +288,29 @@ const deleteProduct = async (index: number) => { getTypeList() } //详情或编辑 -const ReviseOrView = (index: number, row: any , flag : number) => { - ImgArr.value.splice(0,ImgArr.value.length) +const ReviseOrView = (index: number, row: any, flag: number) => { + ImgArr.value.splice(0, ImgArr.value.length) var tempArr = row.goodImg.split(';') - tempArr.forEach((item: any)=>{ + tempArr.forEach((item: any) => { ImgArr.value.push({ url: item }) }) - flag ? (title.value = "编辑商品" , disabled.value = false) : (title.value = "商品详情" , disabled.value = true) + flag ? (title.value = "编辑商品" , disabled.value = false) : (title.value = "商品详情" , disabled.value = true) DialogVisible.value = true; - editForm.value = row; -}; + editForm.value = JSON.parse(JSON.stringify(row)) +} //下架商品 -const handleOff = async (index: number, row: any) => { +const handleOff = async (index: number, row: any) => { row.isShelves ? row.isShelves = 0 : row.isShelves = 1 //三元运算符 改变那一行的上架值 editForm.value = row; - const res = await myAxios.post('/goods/update',{...editForm.value}) - if(res.data.code === 1) { + const res = await myAxios.post('/goods/update', {...editForm.value}) + if (res.data.code === 1) { ElMessage({ - type:'success', - message:'更新成功' + type: 'success', + message: '更新成功' }) - } + } } //处理行数大小变化 const handleSizeChange = (newSize: any) => { @@ -322,19 +336,19 @@ const Exceed_ProductDetail: UploadProps['onExceed'] = (files) => { //覆盖商 const loadForm = (value: any, flag: number) => { flag ? editForm.value.type = value : editForm.value.festivalOrder = value //三元运算符 flag=1 是关于"商品类别"选项的值 flag=0 是关于“是否为节日限定”选项的值 } -const onSearch = (data : String)=>{ //搜索按钮方法 +const onSearch = (data: String) => { //搜索按钮方法 searchParams.value.name = data searchParams.value.current = 1 getProductList() } - //批量删除 -const delBatch = async ()=>{ +//批量删除 +const delBatch = async () => { console.log(idList.value); - const res = await myAxios.post('/goods/delBatch',{ + const res = await myAxios.post('/goods/delBatch', { idList: idList.value }) console.log(res.data); - if(res.data.code === 1) { + if (res.data.code === 1) { ElMessage({ type: 'success', message: '批量删除成功' @@ -344,10 +358,11 @@ const delBatch = async ()=>{ ElMessage.error('删除失败') } } -const handleSelectionChange =()=>{} -const selectChange =(selection: any, row : any)=> { //selction是对象数组,row是当前行对象 - idList.value.splice(0,idList.value.length) //删掉 - selection.forEach((item: any)=> { +const handleSelectionChange = () => { +} +const selectChange = (selection: any, row: any) => { //selction是对象数组,row是当前行对象 + idList.value.splice(0, idList.value.length) //删掉 + selection.forEach((item: any) => { idList.value.push(item.id) }) // console.log('idList--->',idList.value); diff --git a/src/views/Commodity/TypeManagement.vue b/src/views/Commodity/TypeManagement.vue index 50a73ec..5f56cda 100644 --- a/src/views/Commodity/TypeManagement.vue +++ b/src/views/Commodity/TypeManagement.vue @@ -1,32 +1,32 @@ <template> <div style="margin-bottom: 10px;"> <el-button type="success" @click="showForm">添加类别</el-button> - <el-button type="danger" @click="">删除类别</el-button> </div> <el-dialog v-model="dialogVisible" title="商品类别" width="500"> <el-form :model="typeForm" label-width="auto" style="max-width: 600px" v-loading="loading"> <el-form-item label="添加类别图片"> <!-- 下面的event的作用,传入当前事件对象 --> - <el-upload - v-model:file-list="typeImg" - action="#" - list-type="picture-card" - :auto-upload="false" - multiple="true" - :on-remove="handleRemove" - @change="(event: any) => handleChange(event)" - :on-exceed="ExceedTypeImg" - limit="1" > + <el-upload + v-model:file-list="typeImg" + action="#" + ref="uploadProductImg" + list-type="picture-card" + :auto-upload="false" + multiple="true" + :on-remove="handleRemove" + @change="(event: any) => handleChange(event)" + :on-exceed="Exceed_ProductImg" + limit="1"> <el-icon> - <Plus /> + <Plus/> </el-icon> </el-upload> </el-form-item> <el-form-item label="类别名"> - <el-input v-model="typeForm.typeName" /> + <el-input v-model="typeForm.typeName" @input="changeInput"/> </el-form-item> <el-form-item label="备注"> - <el-input v-model="typeForm.typeIntro" /> + <el-input v-model="typeForm.typeIntro" @input="changeInput"/> </el-form-item> </el-form> <template #footer #default="{ row, $index }"> @@ -40,7 +40,7 @@ </el-dialog> <!-- 数据展示层 --> <el-table :data="tableData" border style="width: 100%;" :header-cell-style="{ 'text-align': 'center' }" - @selection-change="handleSelectionChange" :cell-style="{ 'text-align': 'center', 'font-size': '16px' }"> + @selection-change="handleSelectionChange" :cell-style="{ 'text-align': 'center', 'font-size': '16px' }"> <el-table-column type="selection" width="55"></el-table-column> <el-table-column prop="id" label="类别编号" width="150"></el-table-column> <el-table-column prop="typeUrl" label="类别图片" width="300"> @@ -54,8 +54,9 @@ <template #default="scope"> <el-button type="success" @click="editShowForm(scope.$index, scope.row)">修改类别</el-button> <!-- scope.$index是当前行 第一行为0 --> - <el-popconfirm class="ml-5" confirm-button-text='确定' cancel-button-text='取消' icon="InfoFilled" icon-color="red" - title="是否确认删除" @confirm="Delete_type(scope.row.id)" width=180> + <el-popconfirm class="ml-5" confirm-button-text='确定' cancel-button-text='取消' icon="InfoFilled" + icon-color="red" + title="是否确认删除" @confirm="Delete_type(scope.row.id)" width=180> <template #reference> <el-button style="height: 25px" class="ml-5" type="danger">删除类别</el-button> </template> @@ -66,17 +67,18 @@ </template> <script setup lang="ts"> -import { ElMessage, type UploadProps, type UploadUserFile} from 'element-plus'; -import { ErrorInfo, SuccessInfo } from '@/utils/messageInfo'; -import { onMounted, ref } from 'vue' +import {ElMessage, type UploadProps, type UploadUserFile,type UploadFile, genFileId, type UploadRawFile} from 'element-plus'; +import {ErrorInfo, SuccessInfo} from '@/utils/messageInfo'; +import {onMounted, ref} from 'vue' import myAxios from '@/api/myAxios'; + const fileSimple = ref() //单个文件 -const selectedItems = ref([]) +const selectedItems = ref([]) const dialogVisible = ref(false) const submitable = ref(true) //提交按钮禁用状态 const loading = ref(false) //加载 const typeImg: any = ref<UploadUserFile[]>([]) //商品类别图片 -// const imgMap = new Map() //商品类别的map集合 +const uploadProductImg: any = ref() //图片上传的ref绑定 //表单数据 const typeForm = ref({ id: 0, @@ -88,7 +90,7 @@ const typeForm = ref({ const tableData = ref([]) //旗帜 表示点击添加类别(0) 和 点击修改类别两个状态(1),因为我们共用一个表格 const flag = ref(0) -const typeList = ref([]) +const tempImgUrl = ref('') //暂存图片URL //老套路 页面加载必须获取类别列表 onMounted(() => { getTypeList() @@ -120,11 +122,11 @@ const handleChange = async (file: any) => { file: formData.get("file") // 取出formData对象中的file } }) - if ( res.data.code === 1) { + if (res.data.code === 1) { loading.value = false SuccessInfo('上传成功') submitable.value = false - typeForm.value.typeUrl = res.data.data + tempImgUrl.value = res.data.data } else { ErrorInfo(res.data.message) } @@ -133,16 +135,21 @@ const handleChange = async (file: any) => { const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => { console.log(uploadFile, uploadFiles) // typeForm.value.typeUrl = '' - typeImg.value.splice(0,typeImg.value.length) //移除展示即可 + typeImg.value.splice(0, typeImg.value.length) //移除展示即可 submitable.value = true //再禁止上传 } -const ExceedTypeImg: UploadProps['onExceed'] = (files) => { - +//图片上限警告 +const Exceed_ProductImg: UploadProps['onExceed'] = (files) => { //覆盖商品照片 'onExceed'当文件个数超过限制时,做出的判断 + uploadProductImg.value!.clearFiles() + const file = files[0] as UploadRawFile + file.uid = genFileId() + uploadProductImg.value!.handleStart(file) } //新增类别 const showForm = async () => { resetForm() - typeImg.value.splice(0,typeImg.value.length) + tempImgUrl.value = '' + typeImg.value.splice(0, typeImg.value.length) dialogVisible.value = true; flag.value = 0 } @@ -151,11 +158,11 @@ const cancel = () => { dialogVisible.value = false resetForm() } -//新增类别 很繁杂 不知道怎么改 只能不断判空 +//新增类别 const addOrUpdateType = async () => { - //判空(*后期引入对象判空) + //判空 if (typeForm.value.typeName?.indexOf(' ') !== -1 || - typeForm.value.typeName == '' || typeForm.value.typeUrl == '') { + typeForm.value.typeName == '' || tempImgUrl.value == '') { ElMessage({ type: 'warning', message: '不能为空格/空字符串' @@ -165,24 +172,26 @@ const addOrUpdateType = async () => { //取消展示表单 dialogVisible.value = false; if (flag.value === 0) { + console.log('添加的类别--->',typeForm.value) const res = await myAxios.post('/category/add', { //对齐后端请求体 typeName: typeForm.value.typeName, - typeUrl: typeForm.value.typeUrl, + typeUrl: tempImgUrl.value, typeIntro: typeForm.value.typeIntro }) if (res.data.code === 1) { //提交成功后,之间重置表格 + SuccessInfo('添加类别成功') resetForm() } else { ElMessage.error('提交失败') } } - if( flag.value === 1 ) { - const res = await myAxios.post('/category/update',{ - id : typeForm.value.id, + if (flag.value === 1) { + const res = await myAxios.post('/category/update', { + id: typeForm.value.id, typeName: typeForm.value.typeName, - typeUrl: typeForm.value.typeUrl, + typeUrl: tempImgUrl.value, typeIntro: typeForm.value.typeIntro }) if (res.data.code === 1) { @@ -211,19 +220,19 @@ const handleSelectionChange = (row: any) => { } //编辑 const editShowForm = (index: number, row: any) => { - typeImg.value.splice(0,typeImg.value.length) //先删除原先的 + tempImgUrl.value = row.typeUrl //万一上一个上传了没提交编辑 + typeImg.value.splice(0, typeImg.value.length) //先删除原先的 typeImg.value.push({ url: row.typeUrl }) dialogVisible.value = true - typeForm.value = row + typeForm.value = JSON.parse(JSON.stringify(row)) flag.value = 1 - console.log('本行--->',row) } //删除类别 请求体里只传id即可 const Delete_type = async (index: number) => { console.log(typeof index) - const res = await myAxios.post('/category/delete', { id: index }) + const res = await myAxios.post('/category/delete', {id: index}) console.log(res) if (res.data.code === 1) { ElMessage({ @@ -233,12 +242,8 @@ const Delete_type = async (index: number) => { } getTypeList() } -//批量删除类别 -const delBatch = async ()=>{ - console.log(typeList.value); - const res = await myAxios.post('/goods/delBatch',{ - idList: typeList.value - }) +const changeInput = () => { //当输入栏变化时解除禁用提交按钮 + submitable.value = false } </script> diff --git a/src/views/CostumeAppointments/AddCostumes.vue b/src/views/CostumeAppointments/AddCostumes.vue index 21f5b63..df9cf33 100644 --- a/src/views/CostumeAppointments/AddCostumes.vue +++ b/src/views/CostumeAppointments/AddCostumes.vue @@ -31,7 +31,7 @@ </div> <div class="NamePrice"> <div class="name"> - <el-form-item label="体验课名称" prop="name"> + <el-form-item label="服装名称" prop="name"> <el-input v-model="form.name" /> </el-form-item> </div> @@ -118,8 +118,8 @@ const maxArr= ref<Number[]>([]) //最大人数数组 onMounted(() => { getOutfitKind() //获取服装类别 for(let i = 0;i <=50 ; i++) { //初始化人数选择的数组 - minArr.value[i] = 5+i - maxArr.value[i] = 6+i + minArr.value[i] = 1+i + maxArr.value[i] = 2+i } }) const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => { diff --git a/src/views/CostumeAppointments/AppointmentOrder.vue b/src/views/CostumeAppointments/AppointmentOrder.vue index e3f7c1d..3e52a36 100644 --- a/src/views/CostumeAppointments/AppointmentOrder.vue +++ b/src/views/CostumeAppointments/AppointmentOrder.vue @@ -18,12 +18,22 @@ <el-table-column prop="orderNumber" label="订单编号" width="300"></el-table-column> <el-table-column prop="createTime" label="下单时间" width="180"></el-table-column> <el-table-column prop="totalAmount" label="订单实付金额"></el-table-column> - <el-table-column prop="orderStatus" label="订单状态"></el-table-column> + <el-table-column prop="orderStatus" label="订单状态"> + <template #default="scope"> + {{ scope.row.orderStatus === '待发货' ? '待消费' : scope.row.orderStatus }} + </template> + </el-table-column> <el-table-column label="操作" width="220px" fixed="right"> <template #default="scope"> <el-button size="small" @click="showDetail(scope.row)"> 详情 </el-button> + <el-popconfirm confirm-button-text='是' cancel-button-text='否' icon="InfoFilled" icon-color="red" + title="拍摄是否完成?" @confirm="changeOrderStatus(scope.row)" width=180 v-if="['待发货'].includes(scope.row.orderStatus)"> + <template #reference> + <el-button size="small" type="primary" plain>拍摄完成</el-button> + </template> + </el-popconfirm> <el-popconfirm confirm-button-text='确定' cancel-button-text='取消' icon="InfoFilled" icon-color="red" title="确定要退款吗?" @confirm="deleteOrder(scope.row)" width=180> <template #reference> @@ -60,7 +70,6 @@ const searchParams: any = ref({ //封装分页 orderType: 'service' }) const router = useRouter() -const route = useRoute() const loading = ref(false) onMounted(() => { getOrderList() //页面加载获取订单列表 @@ -106,6 +115,9 @@ const showDetail = (row: any) => { } }) }; +const changeOrderStatus = async (row: any) => { //改变订单状态 + const res = await myAxios.post('',{}) +} const deleteOrder = async (row: any) => { //微信退款 loading.value = true console.log('row-->', row) diff --git a/src/views/HomePage/DashBoard.vue b/src/views/HomePage/DashBoard.vue new file mode 100644 index 0000000..d0d7a84 --- /dev/null +++ b/src/views/HomePage/DashBoard.vue @@ -0,0 +1,220 @@ +<template> + <div class="app-container"> + <span style="font-size: 18px">{{ userName }},欢迎</span> + <div class="total-layout"> + <el-row :gutter="20"> + <el-col :span="8"> + <div class="total-frame"> + <img src="../../img/dashBoard/product.png" class="total-icon"> + <div class="total-title">今日商品订单</div> + <div class="total-value">数量:{{ entityOrder }}</div> + <div class="total-value">营业额:¥{{ entityTurnover }}</div> + </div> + </el-col> + <el-col :span="8"> + <div class="total-frame"> + <img src="../../img/dashBoard/课程表.png" class="total-icon"> + <div class="total-title">今日课程订单</div> + <div class="total-value">数量:{{ serviceOrder }}</div> + <div class="total-value">营业额:¥{{ serviceTurnover }}</div> + </div> + </el-col> + <el-col :span="8"> + <div class="total-frame"> + <img src="../../img/dashBoard/3.1拍摄.png" class="total-icon"> + <div class="total-title">今日拍摄订单</div> + <div class="total-value">数量:{{ photoOrder }}</div> + <div class="total-value">营业额:¥{{ photoTurnover }}</div> + </div> + </el-col> + </el-row> + </div> + <div class="un-handle-layout"> + <div class="layout-title">待处理事务</div> + <div class="un-handle-content"> + <el-row :gutter="20"> + <el-col :span="6"> + <div class="un-handle-item"> + <span class="font-medium">待发货订单</span> + <span style="float: right" class="color-danger">{{ waitDeliverOrder }}</span> + </div> + </el-col> + <el-col :span="6"> + <div class="un-handle-item"> + <span class="font-medium">待付款订单</span> + <span style="float: right" class="color-danger">{{ waitPayOrder }}</span> + </div> + </el-col> + <el-col :span="6"> + <div class="un-handle-item"> + <span class="font-medium">待拍摄订单</span> + <span style="float: right" class="color-danger">{{ waitPhotoOrder }}</span> + </div> + </el-col> + <el-col :span="6"> + <div class="un-handle-item"> + <span class="font-medium">待上课订单</span> + <span style="float: right" class="color-danger">{{ waitConsumption }}</span> + </div> + </el-col> + </el-row> + </div> + </div> + <div class="overview-layout"> + <el-row :gutter="20"> + <el-col :span="12"> + <div class="out-border"> + <div class="layout-title">商品总览</div> + <div style="padding: 40px"> + <el-row class="font-medium"> + <el-col :span="8" class="overview-item-title">全部商品</el-col> + <el-col :span="8" class="overview-item-title">已下架</el-col> + <el-col :span="8" class="overview-item-title">已上架</el-col> + </el-row> + <el-row> + <el-col :span="8" class="color-danger overview-item-value">{{ totalProductNum }}</el-col> + <el-col :span="8" class="color-danger overview-item-value">{{ offshelvesNum }}</el-col> + <el-col :span="8" class="color-danger overview-item-value">{{ shelvesNum }}</el-col> + </el-row> + </div> + </div> + </el-col> + </el-row> + </div> + </div> +</template> + +<script setup lang="ts"> +import myAxios from '@/api/myAxios' +import {ref, onMounted} from 'vue' +import {userStore} from "@/store/userStore"; + +let dashBord = new Map() //仪表盘map集合 + +const store = userStore() //用户信息 +const userName = store.loginUser.userName + +const photoTurnover = ref(0) //写真当日营业额 +const photoOrder = ref(0) //写真订单数量 +const entityTurnover = ref(0) //实体类当日营业额 +const entityOrder = ref(0) //实体类当日订单数量 +const serviceTurnover = ref(0) //服务类当日营业额 +const serviceOrder = ref(0) //服务类订单数量 +const totalProductNum = ref(0) //全部商品数量 +const shelvesNum = ref(0) //已上架商品数量 +const offshelvesNum = ref(0) //已下架商品数量 +const waitPhotoOrder = ref(0) //待拍摄订单 +const waitDeliverOrder = ref(0) //待发货订单 +const waitPayOrder = ref(0) //待支付订单数量 +const waitConsumption = ref(0) //待消费订单 +onMounted(() => { + getDashBoard() +}) +const getDashBoard = async () => { + const res = await myAxios.post('/global/queryAll', {}) + // console.log('信息',res.data.data); + if (res.data.code === 1) { + dashBord = new Map(Object.entries(res.data.data)) + photoTurnover.value = dashBord.get('今日写真预约类订单营业额') + photoOrder.value = dashBord.get('今日写真预约订单数') + entityTurnover.value = dashBord.get('今日实体类商品订单营业额') + entityOrder.value = dashBord.get('今日实体类商品订单数') + serviceTurnover.value = dashBord.get('今日服务类商品订单营业额') + serviceOrder.value = dashBord.get('今日服务类商品订单数') + totalProductNum.value = dashBord.get('全部商品数量') + shelvesNum.value = dashBord.get('全部已上架商品数量') + offshelvesNum.value = dashBord.get('全部已下架商品数量') + waitPhotoOrder.value = dashBord.get('写真预约类待拍摄订单') + waitDeliverOrder.value = dashBord.get('实体类待发货订单') + waitPayOrder.value = dashBord.get('所有待支付订单数量') + waitConsumption.value = dashBord.get('服务类待消费订单') + } +} +</script> + +<style scoped> +.app-container { + margin-top: 40px; + margin-left: 120px; + margin-right: 120px; +} + +.total-layout { + margin-top: 20px; +} + +.total-frame { + border: 1px solid #DCDFE6; + border-radius: 10px; + padding: 20px; + height: 100px; +} + +.total-icon { + color: #409EFF; + width: 60px; + height: 60px; +} + +.total-title { + position: relative; + font-size: 20px; + color: #909399; + left: 70px; + top: -60px; +} + +.total-value { + position: relative; + font-size: 18px; + color: #606266; + left: 70px; + top: -45px; +} + +.un-handle-layout { + margin-top: 20px; + border: 1px solid #DCDFE6; + border-radius: 15px; +} + +.layout-title { + color: #606266; + padding: 15px 20px; + background: #F2F6FC; + font-weight: bold; +} + +.un-handle-content { + padding: 20px 40px; +} + +.un-handle-item { + border-bottom: 1px solid #EBEEF5; + padding: 10px; +} + +.un-handle-item { + border-bottom: 1px solid #EBEEF5; + padding: 10px; +} + +.overview-layout { + margin-top: 20px; +} + +.out-border { + border: 1px solid #DCDFE6; + border-radius: 15px; +} + +.overview-item-value { + font-size: 24px; + text-align: center; +} + +.overview-item-title { + margin-top: 10px; + text-align: center; +} +</style> \ No newline at end of file diff --git a/src/views/Login.vue b/src/views/Login.vue index 68add61..3341863 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -66,8 +66,8 @@ SuccessInfo('登陆成功') //将用户信息放入pinia await store.getLoginUser(res.data.data) - //跳转个人中心 - await router.replace('/PersonalCenter') + //跳转仪表盘 + await router.replace('/DashBoard') } else { WarnInfo(res.data.message) return; //空返回结束函数 diff --git a/src/views/Orders/OrderList.vue b/src/views/Orders/OrderList.vue index e6d726b..478b13f 100644 --- a/src/views/Orders/OrderList.vue +++ b/src/views/Orders/OrderList.vue @@ -2,7 +2,7 @@ <div style="margin-bottom: 20px"> <el-input style="width: 250px; height: 30px; margin-right: 10px; font-size: 14px" suffix-icon="Search" placeholder="请输入订单编号" v-model="orderNumber"></el-input> - <el-button class="ml-5" type="primary" @click="load" style="height: 30px;">搜索</el-button> + <el-button class="ml-5" type="primary" @click="load(orderNumber)" style="height: 30px;">搜索</el-button> <el-button type="warning" @click="reset" style="height:30px">重置</el-button> </div> <!-- 数据展示层 --> @@ -278,7 +278,11 @@ const deleteOrder = async (row: any) => { //微信退款 const reset = () => { //重置搜索框 orderNumber.value = ''; }; -const load = () => { } //搜索的方法 +const load = (onum : any) => { //搜索的方法 + searchParams.value.orderNumber = onum + searchParams.value.current = 1 + getOrderList() +} const cancelOrder = async (row: any) => { //取消订单的方法(未支付能取消) console.log('点击的这一行--->', row); const res = await myAxios.post('/order/cancel/id', { id: row.id }) diff --git a/src/views/Person.vue b/src/views/Person.vue deleted file mode 100644 index 2eca115..0000000 --- a/src/views/Person.vue +++ /dev/null @@ -1,32 +0,0 @@ -<template> - <el-card style="width: 500px"> - <el-form label-width="80px" size="small"> - <el-form-item label="用户名"> - <el-input v-model="form.username" autocomplete="off"></el-input> - </el-form-item> - <el-form-item label="学号"> - <el-input v-model="form.nickname" autocomplete="off"></el-input> - </el-form-item> - <el-form-item label="邮箱"> - <el-input v-model="form.email" autocomplete="off"></el-input> - </el-form-item> - <el-form-item label="电话"> - <el-input v-model="form.phone" autocomplete="off"></el-input> - </el-form-item> - <el-form-item label="地址"> - <el-input v-model="form.address" autocomplete="off"></el-input> - </el-form-item> - <el-form-item> - <el-button type="primary" @click="save">确 定</el-button> - </el-form-item> - </el-form> - </el-card> -</template> - -<script> - -</script> - -<style scoped> - -</style> \ No newline at end of file diff --git a/src/views/ServiceType/AddServiceProduct.vue b/src/views/ServiceType/AddServiceProduct.vue index 406ee32..86d794e 100644 --- a/src/views/ServiceType/AddServiceProduct.vue +++ b/src/views/ServiceType/AddServiceProduct.vue @@ -36,8 +36,9 @@ </el-form-item> </div> <div class="price"> - <el-form-item label="体验课价格" prop="price"> - <el-input v-model="form.price" style="width: 90px;" /> + <el-form-item label="产品价格" prop="price"> + <el-input-number v-model="form.price" min="0" :precision="2" :step="0.5" /> + <p>元</p> </el-form-item> </div> </div> @@ -103,7 +104,7 @@ const onSubmit = async () => { const values = Object.values(form.value); // 使用some()方法来检查是否有任何值为空 console.log(form.value.appointmentDateAddRequestList) - if (values.some(value => value === null || value === undefined || value === '') || form.value.appointmentDateAddRequestList.length == 0) { + if (values.some(value => value === null || value === undefined || value === ''|| value === 0) || form.value.appointmentDateAddRequestList.length == 0 ) { ElMessage({ type: 'warning', message: '请检查表单数据是否完整填写' diff --git a/src/views/ServiceType/ProductCenter.vue b/src/views/ServiceType/ProductCenter.vue index e8b269d..537f366 100644 --- a/src/views/ServiceType/ProductCenter.vue +++ b/src/views/ServiceType/ProductCenter.vue @@ -348,7 +348,7 @@ const ReviseOrView = (index: number, row: any , flag : number) => { //flag值不同显示不同内容 disabled开启和关闭 flag ? (title.value = "编辑商品" , disabled.value = false) : (title.value = "商品详情" , disabled.value = true) DialogVisible.value = true; - editForm.value = row; + editForm.value = JSON.parse(JSON.stringify(row)); }; //下架商品(待优化,有问题,逻辑有问题) const handleOff = async (row: any) => { diff --git a/src/views/User/PersonalCenter.vue b/src/views/User/PersonalCenter.vue index 763c907..cb58147 100644 --- a/src/views/User/PersonalCenter.vue +++ b/src/views/User/PersonalCenter.vue @@ -1,11 +1,115 @@ -<script setup lang="ts"> - -</script> <template> -个人中心 +<div class="detail-container"> + <el-card shadow="hover"> + <el-form label-width="100px" :disabled="disabled"> + <el-form-item label="头像"> + <el-upload v-model:file-list="ImgArr" ref="uploadProductImg" action="#" list-type="picture-card" + :auto-upload="false" multiple="true" :on-remove="removePic" @change="(event: any) => handleChange(event)" + :on-exceed="Exceed_ProductImg" limit="1"> + <el-icon> + <Plus /> + </el-icon> + </el-upload> + </el-form-item> + <div style="display: flex;"> + <el-form-item label="账号"> + <el-input v-model="userForm.userAccount"></el-input> + </el-form-item> + <el-form-item label="密码"> + <el-input v-model="userForm.userPassword" /> + </el-form-item> + </div> + <div style="display: flex;"> + <el-form-item label="用户名"> + <el-input v-model="userForm.userName" /> + </el-form-item> + <el-form-item label="手机号码"> + <el-input v-model="userForm.phone" /> + </el-form-item> + </div> + <div style="display: flex;"> + <el-form-item label="积分"> + <el-input v-model="userForm.points"></el-input> + </el-form-item> + </div> + </el-form> + <div style="display: flex;"> + <el-button @click="changeStatus">{{ btnText }}</el-button> + <el-button type="primary" @click="saveEdit" :disabled="disabled">确认</el-button> + </div> + </el-card> +</div> </template> +<script setup lang="ts"> +import { ElMessage, type UploadProps, type UploadUserFile,type UploadFile, genFileId, type UploadRawFile } from 'element-plus'; +import myAxios from '@/api/myAxios'; +import { ref, onMounted } from 'vue' +import { ErrorInfo, SuccessInfo, WarnInfo } from '@/utils/messageInfo'; + +const ImgArr: any = ref<UploadUserFile[]>([]) //给商品中心页面编辑商品使用 +const disabled = ref(true) //表单是否禁用 +const userForm: any = ref({}) //用户表单 +const fileSimple = ref() //单个文件 +const uploadProductImg: any = ref() //图片上传的ref绑定 +const tempAvatar = ref('') //暂存的用户头像 +const btnText = ref('编辑') //编辑按钮 +const tempUserObj = ref({}) //暂存的用户对象 +//图片上限警告 +const Exceed_ProductImg: UploadProps['onExceed'] = (files) => { //覆盖商品照片 'onExceed'当文件个数超过限制时,做出的判断 + uploadProductImg.value!.clearFiles() + const file = files[0] as UploadRawFile + file.uid = genFileId() + uploadProductImg.value!.handleStart(file) +} + +//上传图片方法 +const handleChange = async (file: any) => { + fileSimple.value = file + let formData = new FormData() //这一步很重要 创建一个FormData对象 + formData.append("file", fileSimple.value.raw) //fileSimple.value.raw 才是文件主体 将其以文件的格式插入formData + const res = await myAxios({ //编写请求,与以前的请求不同,这一次要指定好头部类型和文件类型 + url: '/file/upload/server/not_login', + method: 'post', + headers: { + 'content-Type': 'multipart/form-data' + }, + data: { + biz: "test", + file: formData.get("file") // 取出formData对象中的file + } + }) + if (res.data.code === 1) { + tempAvatar.value = res.data.data + } +} + +//移除图片方法 +const removePic: UploadProps['onRemove'] = (uploadFile, uploadFiles) => { //uploadFile表示当前删除的图片,uploadFiles是还剩余的图片信息 + userForm.value.userAvatar = '' +} + +const saveEdit = async ()=>{ //保存用户信息 + +} + +const changeStatus = async ()=> { + if(btnText.value === '编辑') { + btnText.value = '取消' + disabled.value = false + } else { + btnText.value = '编辑' + disabled.value = true + //还差一步数据回显 + } +} +</script> + <style scoped> - +.detail-container { + width: 80%; + padding: 20px 20px 20px 20px; + margin: 20px auto; +} </style> \ No newline at end of file diff --git a/src/views/User/UserManagement.vue b/src/views/User/UserManagement.vue index 24f31e9..55caf98 100644 --- a/src/views/User/UserManagement.vue +++ b/src/views/User/UserManagement.vue @@ -1,80 +1,87 @@ <template> - <div> - - <div style="margin: 10px 0"> - <el-input style="width: 200px; height: 30px; margin-right: 10px;" suffix-icon="Search" placeholder="请输入用户名" v-model="username"></el-input> - <el-button class="ml-5" type="primary" @click="onSearch(username)" style="height: 25px;">搜索</el-button> - <el-button type="warning" @click="reset" style="height:25px">重置</el-button> - </div> -<!-- <div style="margin: 15px 0">--> -<!-- <el-button class="ml-5" type="primary" @click="handleAdd" style="height: 25px;">新增 <el-icon style="margin-left: 5px"><CirclePlus /></el-icon></el-button>--> - -<!-- <el-popconfirm--> -<!-- class="ml-5"--> -<!-- confirm-button-text='确定'--> -<!-- cancel-button-text='取消'--> -<!-- icon="InfoFilled"--> -<!-- icon-color="red"--> -<!-- title="您确定批量删除这些数据吗?"--> -<!-- @confirm="delBatch"--> -<!-- width=180--> -<!-- >--> -<!-- <template #reference>--> -<!-- <el-button style="height: 25px" class="ml-5" type="danger" slot="reference">批量删除 <el-icon style="margin-left: 5px;"><Remove /></el-icon></el-button>--> -<!-- </template>--> -<!-- </el-popconfirm>--> -<!-- </div>--> - <el-table :data="tableData" border stripe header-cell-class-name="headerBg" :cell-style="{textAlign: 'center'}" - @selection-change="handleSelectionChange" :header-cell-style="{'text-align': 'center'}"> - <el-table-column type="selection" width="55"></el-table-column> - <el-table-column prop="id" label="序号" width="50"></el-table-column> - <el-table-column prop="userName" label="用户昵称" ></el-table-column> - <el-table-column prop="userAvatar" label="头像"> - <template #default="scope"><img :src="scope.row.userAvatar" alt="" style="height: 50px;"></template> - </el-table-column> - <el-table-column prop="userRole" label="身份"></el-table-column> - <el-table-column prop="phone" label="手机号"></el-table-column> - <el-table-column label="操作"> - <!-- <template slot-scope="scope"> - <el-button type="success" @click="detail(scope.row)">详情 <i class="el-icon-edit"></i></el-button> - - <el-popconfirm - class="ml-5" - confirm-button-text='确定' - cancel-button-text='取消' - icon="el-icon-info" - icon-color="red" - title="您确定删除吗?" - @confirm="del(scope.row.id)" - > - <el-button type="danger" slot="reference">封禁 <i class="el-icon-remove-outline"></i></el-button> - </el-popconfirm> - - </template> --> - </el-table-column> - </el-table> - <!-- 分页查询 --> - <div style="padding: 10px 0"> - <el-pagination - :current-page="searchParams.current" - :page-size="searchParams.pageSize" - :page-sizes="[2, 5, 10, 20]" - @size-change="handleSizeChange" - @current-change="handleCurrentChange" - :small="null" - background - layout="total, sizes, prev, pager, next, jumper" - :total="total" - /> - </div> + <div style="margin: 10px 0"> + <el-input style="width: 200px; height: 30px; margin-right: 10px;" suffix-icon="Search" placeholder="请输入用户名" + v-model="username"></el-input> + <el-button class="ml-5" type="primary" @click="onSearch(username)" style="height: 25px;">搜索</el-button> + <el-button type="warning" @click="reset" style="height:25px">重置</el-button> </div> + <el-table :data="tableData" border stripe header-cell-class-name="headerBg" :cell-style="{ textAlign: 'center' }" + @selection-change="handleSelectionChange" :header-cell-style="{ 'text-align': 'center' }"> + <el-table-column type="selection" width="55"></el-table-column> + <el-table-column prop="id" label="序号" width="50"> + <template #default="{ $index }"> + {{ $index + 1 }} + </template> + </el-table-column> + <el-table-column prop="userName" label="用户昵称"></el-table-column> + <el-table-column prop="userAvatar" label="头像"> + <template #default="scope"><img :src="scope.row.userAvatar" alt="" style="height: 50px;"></template> + </el-table-column> + <el-table-column prop="userRole" label="身份"> + <template #default="scope"> + {{ scope.row.userRole === 'boss' ? '管理员' : '小程序用户' }} + </template> + </el-table-column> + <el-table-column prop="phone" label="手机号"></el-table-column> + <el-table-column prop="isDelete" label="是否删除"></el-table-column> + <el-table-column label="操作"> + <template #default="scope"> + <el-button size="small" @click="checkDetail(scope.row)">详情</el-button> + <el-button size="small" type="primary" @click="editUser(scope.row)">编辑</el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页查询 --> + <div style="padding: 10px 0"> + <el-pagination :current-page="searchParams.current" :page-size="searchParams.pageSize" :page-sizes="[2, 5, 10, 20]" + @size-change="handleSizeChange" @current-change="handleCurrentChange" :small="null" background + layout="total, sizes, prev, pager, next, jumper" :total="total" /> + </div> + <!-- 单个用户表单 --> + <el-dialog v-model="DialogVisible" :title="title"> + <el-form label-width="100px" :disabled="disabled"> + <el-form-item label="头像"> + <el-upload v-model:file-list="ImgArr" ref="uploadProductImg" action="#" list-type="picture-card" + :auto-upload="false" multiple="true" :on-remove="removePic" @change="(event: any) => handleChange(event)" + :on-exceed="Exceed_ProductImg" limit="1"> + <el-icon> + <Plus /> + </el-icon> + </el-upload> + </el-form-item> + <el-form-item label="账号"> + <el-input v-model="userForm.userAccount" style="width: 200px;"></el-input> + </el-form-item> + <el-form-item label="密码"> + <el-input v-model="userForm.userPassword" /> + </el-form-item> + <div style="display: flex;"> + <el-form-item label="用户名"> + <el-input v-model="userForm.userName" /> + </el-form-item> + <el-form-item label="手机号码"> + <el-input v-model="userForm.phone" /> + </el-form-item> + </div> + <div style="display: flex;"> + <el-form-item label="积分"> + <el-input v-model="userForm.points"></el-input> + </el-form-item> + </div> + </el-form> + <template #footer> + <el-button @click="DialogVisible = false" :disabled="disabled">取消</el-button> + <el-button type="primary" @click="saveEdit" :disabled="disabled">确认</el-button> + </template> + </el-dialog> </template> <script setup lang="ts"> -import { ElMessage } from 'element-plus'; +import { ElMessage, type UploadProps, type UploadUserFile,type UploadFile, genFileId, type UploadRawFile } from 'element-plus'; import myAxios from '@/api/myAxios'; -import {ref, onMounted , inject} from 'vue' - +import { ref, onMounted, inject } from 'vue' +import { ErrorInfo, SuccessInfo, WarnInfo } from '@/utils/messageInfo'; +const ImgArr: any = ref<UploadUserFile[]>([]) //给商品中心页面编辑商品使用 //获取的所有数据 const tableData = ref([]) //筛选条数 @@ -86,60 +93,135 @@ const searchParams: any = ref({ //每页显示条数 pageSize: 5 }) -//导入组件刷新 -const reload : any = inject("reload") +const reload: any = inject("reload") //导入组件刷新 +const DialogVisible = ref(false) //是否显示表格 +const title = ref('编辑用户') //表单标题 +const disabled = ref(false) //表单是否禁用 +const userForm: any = ref({}) //用户表单 +const fileSimple = ref() //单个文件 +const uploadProductImg: any = ref() //图片上传的ref绑定 +const tempAvatar = ref('') //暂存次行的用户头像 onMounted(() => { getUserList() }) const username = ref('') //重置按钮 -const reset =()=>{ +const reset = () => { reload() } +//上传图片方法 +const handleChange = async (file: any) => { + fileSimple.value = file + let formData = new FormData() //这一步很重要 创建一个FormData对象 + formData.append("file", fileSimple.value.raw) //fileSimple.value.raw 才是文件主体 将其以文件的格式插入formData + const res = await myAxios({ //编写请求,与以前的请求不同,这一次要指定好头部类型和文件类型 + url: '/file/upload/server/not_login', + method: 'post', + headers: { + 'content-Type': 'multipart/form-data' + }, + data: { + biz: "test", + file: formData.get("file") // 取出formData对象中的file + } + }) + if (res.data.code === 1) { + tempAvatar.value = res.data.data + } +} +//移除图片方法 +const removePic: UploadProps['onRemove'] = (uploadFile, uploadFiles) => { //uploadFile表示当前删除的图片,uploadFiles是还剩余的图片信息 + userForm.value.userAvatar = '' +} +//图片上限警告 +const Exceed_ProductImg: UploadProps['onExceed'] = (files) => { //覆盖商品照片 'onExceed'当文件个数超过限制时,做出的判断 + uploadProductImg.value!.clearFiles() + const file = files[0] as UploadRawFile + file.uid = genFileId() + uploadProductImg.value!.handleStart(file) +} //用户信息列表 const getUserList = async () => { //为什么要用展开表达式({...}),因为是POST请求,如果直接对象.value,传的是Object类型 - const res = await myAxios.post('/user/list/page/vo',{...searchParams.value}) - if(res.data.code === 1) { - console.log(res.data.data) - //给前端表格赋值 字段名一定要对应 - tableData.value = res.data.data.records - //筛选条数 - total.value = parseInt(res.data.data.total) - }else { - ElMessage({ - type: 'info', - message: '查询失败', - }) - } + const res = await myAxios.post('/user/list/page', { ...searchParams.value }) + if (res.data.code === 1) { + console.log(res.data.data) + //给前端表格赋值 字段名一定要对应 + tableData.value = res.data.data.records + //筛选条数 + total.value = parseInt(res.data.data.total) + } else { + ElMessage({ + type: 'info', + message: '查询失败', + }) + } } -const handleSelectionChange = (val:any)=>{ +const handleSelectionChange = (val: any) => { console.log(val) } // 处理行数大小变化 -const handleSizeChange = (newSize:any) => { +const handleSizeChange = (newSize: any) => { searchParams.value.pageSize = newSize //新的页面条数 getUserList() //重新发起请求 }; // 处理当前页变化 -const handleCurrentChange = (Current:any) => { +const handleCurrentChange = (Current: any) => { searchParams.value.current = Current //新的当前页面 getUserList() //重新发起请求 }; //搜索按钮方法 -const onSearch = (data : String)=>{ +const onSearch = (data: String) => { searchParams.value.userName = data searchParams.value.current = 1 getUserList() } - +const checkDetail = (obj: any) => { //查看详情方法 + title.value = '查看用户' + ImgArr.value.splice(0, ImgArr.value.length) + ImgArr.value.push({ + url: obj.userAvatar + }) + disabled.value = true + DialogVisible.value = true + userForm.value = obj +} +const editUser = (obj: any) => { //编辑方法 + tempAvatar.value = userForm.value.userAvatar //暂存 + disabled.value = false + title.value = '编辑用户' + ImgArr.value.splice(0, ImgArr.value.length) + ImgArr.value.push({ + url: obj.userAvatar + }) + DialogVisible.value = true + userForm.value = obj +} +const saveEdit = async () => { //更新用户信息 + console.log('编辑后的信息--->', userForm.value); + const res = await myAxios.post('/user/update', { + id: 2, + userPassword: userForm.value.userPassword, + userName: userForm.value.userName, + userAvatar: tempAvatar.value, + phone: userForm.value.phone, + userRole: userForm.value.userRole + }) + if(res.data.code === 1) { + SuccessInfo('更新成功') + DialogVisible.value = false + getUserList() + } else { + ErrorInfo('更新失败') + } +} </script> <style scoped> -.headerBg{ +.headerBg { background-color: #eee !important; } </style> \ No newline at end of file diff --git a/tsconfig.app.json b/tsconfig.app.json index c777231..b59170f 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -1,6 +1,6 @@ { "extends": "@vue/tsconfig/tsconfig.dom.json", - "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "include": ["env.d.ts", "src/**/*"], "exclude": ["src/**/__tests__/*"], "compilerOptions": { "composite": true, @@ -10,5 +10,6 @@ "paths": { "@/*": ["./src/*"] } - } + }, + "moduleResolution" : "node" }