# Conflicts:
#	src/views/test.vue
This commit is contained in:
sa_10_0 2024-12-19 18:57:27 +08:00
commit 07e41ce272
16 changed files with 744 additions and 365 deletions

View File

@ -6,17 +6,27 @@
<script setup lang="ts">
//
import { provide , nextTick , ref } from 'vue'
import { provide , nextTick , ref , onMounted } from 'vue'
import { ElConfigProvider } from 'element-plus'
import router from './router';
import zhCn from 'element-plus/es/locale/lang/zh-cn' //ElemenetPlus
import myAxios from './api/myAxios';
const isRouterActive = ref(true)
provide('reload', () => {
provide('reload', () => { //
isRouterActive.value = false
nextTick(() => {
isRouterActive.value = true
})
})
onMounted(()=>{
checkLoginState()
})
const checkLoginState = async ()=>{ //
const res = await myAxios.get('/user/get/login')
if(res.data.code != 1) {
router.push('/')
}
}
</script>

View File

@ -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' //测试服务器
});
// 添加请求拦截器
axios.interceptors.request.use(function (config) {

View File

@ -0,0 +1,80 @@
<template>
<div style="margin-bottom: 20px;">选择当天时间段和人数</div>
<div v-for="(item,index) in timeArr">
<span>选择时间段</span>
<!-- <el-time-picker
v-model="timePickArr[index]"
format='HH:mm'
is-range="true"
range-separator="到"
start-placeholder="开始"
end-placeholder="结束"
value-format="HH:mm"
:style="{ width: '236px' }"
@change="saveTime(index)"
/> -->
<div>
<span>最小人数:</span>
<el-select v-model="timeArr.minNumber" style="width: 100px" @change="minNum(index)">
</el-select>
<span>最大人数:</span>
<el-select v-model="timeArr.maxNumber" style="width: 100px" @change="maxNum(index)">
</el-select>
<el-button circle @click="addList(index)"><el-icon>
<Plus />
</el-icon></el-button>
<el-button circle @click="subList(index)" v-if="index > 0"><el-icon>
<Minus />
</el-icon></el-button>
</div>
</div>
<el-button size="small" @click="printInfo()">
打印
</el-button>
</template>
<script setup lang="ts">
import { ref,onMounted,defineEmits } from 'vue';
import { ElMessage } from 'element-plus';
const fatherCom : any = defineProps(['timeObject']) //
const timeArr : any = ref(fatherCom.timeObject) //
onMounted(()=>{
})
const saveTime =(index:number)=>{
}
const addList =(index:number)=>{}
const subList =(index:number)=>{}
const minNum =(index : number)=>{ //
if(false) {
ElMessage({
type: 'warning',
message: '最小人数不能大于最大人数'
})
return;
}
}
const maxNum =(index : number)=>{
if(false) {
ElMessage({
type: 'warning',
message: '最大人数不能小于最小人数'
})
return;
}
}
const printInfo =()=>{
// console.log('timePickArr-->',timePickArr.value);
console.log('timeArr-->',timeArr.value);
// console.log(fatherCom);
// let tempArr = timeArr.value[0].timeSlot.split("-")
// timePickArr.value.push(tempArr)
// console.log(timePickArr.value);
}
</script>
<style scoped>
</style>

View File

@ -157,6 +157,7 @@ const drawerOpen =()=>{ //抽屉打开时
if(isTrue.value) {
periodObj.value = periodMap.get(periodObj.value.specificDate)
timePickArr.value= timePickMap.get(periodObj.value.specificDate)
console.log('timePickArr--->',timePickArr.value);
}
}
const resetForm =()=>{ //

View File

@ -1,92 +0,0 @@
import { ElMessage } from 'element-plus';
const isNotValid = (val) => {
const timeRegex = /^([0-1]?[0-9]|2[0-3]):([0-5]?[0-9])-(?:[0-1]?[0-9]|2[0-3]):([0-5]?[0-9])$/;
const rangeRegex = /^\(\d+,\d+\)$/
return timeRegex.test(val.timeSlot) && rangeRegex.test(val.numberRange)
}
const isValidPlus = (val) => {
const timeRegex = /^([0-1]?[0-9]|2[0-3]):([0-5]?[0-9])-(?:[0-1]?[0-9]|2[0-3]):([0-5]?[0-9])$/;
const rangeRegex = /^\(\d+,\d+\)$/
if(val.timeSlot === '' && val.numberRange === '') return false
if(timeRegex.test(val.timeSlot) && rangeRegex.test(val.numberRange)) return false
return true
}
export const transfer = (val, arr, isAvailableArr) => {
console.log('这是val:', val)
for (var i = 0; i < val.length; i ++ ) {
for (var j = 0; j < val[i].length; j ++ ) {
arr[i][j].timeSlot = val[i][j].startTime + "-" + val[i][j].endTime
arr[i][j].numberRange = "(" + val[i][j].minNumValue + "," + val[i][j].maxNumValue + ")"
}
}
console.log('这是arr:', arr)
for (var i = 0; i < 4; i ++ ) {
for (var j = 0; j < 6; j ++ ) {
if(isValidPlus(arr[i][j])) {
ElMessage({
type: 'error',
message: '请检查表单数据是否完整填写'
})
return ;
}
}
}
let newArr = new Array(4)
for (var i = 0; i < 4; i ++ ) {
newArr[i] = {
timeSlot:'',
numberRange: '',
isAvailable: false
}
}
let timeSlotArr = []
let numberRangeArr = []
let cnt = 0
let k = 0
for (var i = 0; i < val.length; i ++ ) {
for (var j = 0; j < val[i].length; j ++ ) {
if(isNotValid(arr[i][j])) {
timeSlotArr.push(arr[i][j].timeSlot)
numberRangeArr.push(arr[i][j].numberRange)
}
}
if(val[i].length == 0){
newArr[i].timeSlot = "00:00-00:00"
newArr[i].numberRange = "(0,0)"
newArr[i].isAvailable = 0
k ++
cnt ++
}else{
newArr[i].timeSlot = timeSlotArr.join(';')
newArr[i].numberRange = numberRangeArr.join(';')
newArr[i].isAvailable = isAvailableArr[i] ? 1 : 0
if(!isAvailableArr[i]) k ++
}
if(cnt == 4) {
ElMessage({
type: 'error',
message: '至少得有一个预约时间段'
})
return ;
}
if(k == 4) {
ElMessage({
type: 'error',
message: '至少有一天可以预约'
})
return ;
}
timeSlotArr = []
numberRangeArr = []
}
ElMessage({
type: 'success',
message: '时间段保存成功'
})
// console.log(newArr)
return newArr
}

View File

@ -0,0 +1,26 @@
import { saveBtn, invInput } from './globalVar';
export const validateName = (rule: any, value: any, callback: any) => { //商品名称的校验规则
if (value === '') {
callback(new Error('请输入商品名称'))
} else if (value.length < 2) {
callback(new Error('商品名称不能小于两位'))
saveBtn.value = true
} else { saveBtn.value = false }
}
export const validateIntro = (rule: any, value: any, callback: any) => { //商品简介的校验规则
if (value === '') {
callback(new Error('请输入商品简介'))
} else if (value.length < 20) {
callback(new Error('商品简介不能少于20字'))
saveBtn.value = true
} else { saveBtn.value = false }
}
export const validateDetail = (rule: any, value: any, callback: any) => {
if (value === '') {
callback(new Error('请输入商品详情'))
} else if (value.length < 80) {
callback(new Error('商品详情不能少于80字'))
saveBtn.value = true
} else { saveBtn.value = false }
}

View File

@ -0,0 +1,5 @@
import { ref } from "vue";
export const saveBtn = ref(false) //提交按钮状态
export const invInput = ref(false) //库存按钮

View File

@ -0,0 +1,70 @@
import { ref } from 'vue';
import myAxios from '@/api/myAxios';
import { type UploadFile, type UploadProps, genFileId, type UploadRawFile, type FormInstance, type FormRules } from 'element-plus';
import { WarnInfo } from '../messageInfo';
export const productImgMap = new Map() //商品图片数组
export const productImgArr: any = ref([])
export const fileSimple = ref() //单个文件
export const form : any = ref({ //添加实体类商品的表单
name: '', //商品名称
price: '', //商品价格
intro: '',//产品简介
festivalName: '', //节日名称
type: '',//类别
label: '',//商品标签
introDetail: '',//详情描述
goodImg: '', //商品图片url
detailImg: '', //图文详情url
inventory: '' //库存
})
//图片上传请求 此请求只要选择了图片,就会默认上传
export const handleChange = async (file: any, flag: number) => { //12.18改
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",
// 取出formData对象中的file
file: formData.get("file")
}
})
if (res.data.code === 1) {
if (flag === 0) {
productImgArr.value.splice(0, productImgArr.value.length) //一并删除数组中存放的图片Url地址
productImgMap.set(fileSimple.value.uid, res.data.data)
productImgMap.forEach(loopMap) //将图片url插入到数组中
form.value.goodImg = formatString()
} else {
form.value.detailImg = res.data.data
}
}
}
const formatString = () => { //拼接图片URL,方便传给后端
var str = ''
str = productImgArr.value.join(';')
return str
}
const loopMap = (value: any, key: any, map: any) => { //循环商品图片Map集合函数,用于给请求的字段赋值
productImgArr.value.push(value)
}
export const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => { //uploadFile表示当前删除的图片uploadFiles是还剩余的图片信息
productImgMap.delete(uploadFile.uid)
productImgArr.value.splice(0, productImgArr.value.length) //一并删除数组中存放的图片Url地址
productImgMap.forEach(loopMap)
form.value.goodImg = formatString()
}
export const Exceed_ProductImg: UploadProps['onExceed'] = (files) => { //覆盖商品照片 'onExceed'当文件个数超过限制时,做出的判断
WarnInfo('最多只能上传七张图片!')
}

29
src/utils/messageInfo.ts Normal file
View File

@ -0,0 +1,29 @@
import { ElMessage } from 'element-plus';
export const SuccessInfo = (message: any)=>{ //成功的提示
ElMessage({
type: 'success',
message: message
})
}
export const ErrorInfo = (message: any)=>{ //错误的提示
ElMessage({
type: 'error',
message: message
})
}
export const WarnInfo = (message: any) =>{ //警告的提示
ElMessage({
type: 'warning',
message: message
})
}
export const CommInfo =(message: any)=>{ //普通提示
ElMessage({
type: 'info',
message: message
})
}

View File

@ -1,194 +1,211 @@
<template>
<div>
<div class="totalBox">
<!-- 表单 ref prop绑定 用于重置表单 -->
<el-form ref="resetFormData" :model="form" label-width="auto" style="width: 750px" size="large">
<div class="fromBox">
<el-form ref="resetFormData" :model="form" label-width="auto" size="large" :rules="rules">
<div>
<el-form-item label="添加商品图片">
<!-- 下面的event的作用,传入当前事件对象 -->
<el-upload
ref="uploadProductImg"
action="#"
list-type="picture-card"
:auto-upload="false"
multiple="true"
:on-remove="handleRemove"
@change="(event: any) => handleChange(event, 0)"
:on-exceed="Exceed_ProductImg"
limit="1" >
<el-upload ref="uploadProductImg" action="#" list-type="picture-card" :auto-upload="false" multiple="true"
:on-remove="handleRemove" @change="(event: any) => handleChange(event, 0)" :on-exceed="Exceed_ProductImg"
limit="7">
<el-icon>
<Plus />
</el-icon>
</el-upload>
</el-form-item>
</div>
<!-- 添加图文描述-->
<div>
<el-form-item label="添加图文描述">
<el-upload
ref="uploadProductDetail"
action="#"
list-type="picture-card"
:auto-upload="false"
multiple="true"
:on-change="(event: any) => handleChange(event, 1)"
:on-exceed="Exceed_ProductDetail"
limit="1"
:on-remove="handleRemove"
>
<el-upload ref="uploadProductDetail" action="#" list-type="picture-card" :auto-upload="false"
multiple="true" :on-change="(event: any) => handleChange(event, 1)" :on-exceed="Exceed_ProductDetail"
limit="1" :on-remove="handleRemove">
<el-icon>
<Plus />
</el-icon>
</el-upload>
</el-form-item>
</div>
<div class="NamePrice">
<el-form-item label="产品名称" prop="name">
<el-input v-model="form.name" />
<el-input v-model="form.name" maxlength="12" minlength="2" show-word-limit style="width: 260px;" />
</el-form-item>
<el-form-item label="产品价格" prop="price">
<el-input v-model="form.price" />
<el-input-number v-model="form.price" min="0.01" :precision="2" :step="0.5" />
<p></p>
</el-form-item>
</div>
<div class="IntroInven">
<el-form-item label="产品简介" prop="intro">
<el-input v-model="form.intro" />
<el-input v-model="form.intro" type="textarea" placeholder="产品尺寸,服务等" maxlength="30" show-word-limit
style="width: 300px;" />
</el-form-item>
<el-form-item label="当前库存" prop="inventory">
<el-input v-model="form.inventory" />
<div>
<el-form-item label="库存" prop="inventory">
<el-input-number v-model="form.inventory" min="0" :precision="0" :step="1" :disabled="invInput" />
</el-form-item>
<el-form-item label="是否为限定类产品" prop="festivalOrder">
<el-select v-model="form.festivalOrder" placeholder="请选择" @change="(event: any) => loadForm(event, 0)">
<el-option label="是" value="1" />
<el-option label="否" value="0" />
</el-select>
</el-form-item>
<!-- <el-form-item v-if="form.region=='ture' " label="节日名称">
</div>
</div>
<div class="festivalBox">
<el-form-item label="节日名称" prop="festivalName" style="width: 300px;">
<el-input v-model="form.festivalName" />
</el-form-item> -->
<el-form-item label="产品类别" prop="type">
<el-select v-model="typeList.value" placeholder="请选择" @change="(event: any) => loadForm(event, 1)">
<el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value1" />
</el-form-item>
<el-form-item label="产品类别" prop="type" style="width: 240px;">
<el-select v-model="form.type" placeholder="请选择" @change="(event: any) => loadForm(event)" :disabled="typeSelect">
<el-option v-for="item in typeList" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<div>
<el-checkbox v-model="isqualify" label="定制商品" size="large" border style="margin-left: 10px;" @change="customTag" />
</div>
</div>
<el-form-item label="商品标签" prop="label">
<el-input v-model="form.label" type="textarea" placeholder="" />
<div v-for="(item, index) in labelList" :key="index">
<el-input v-model="labelList[index]" type="text" style="width: 150px;" maxlength="5" show-word-limit
@blur="addLabelList" />
</div>
<el-button type="primary" @click="addLabel">添加</el-button>
</el-form-item>
<el-form-item label="商品详细描述" prop="introDetail">
<el-input v-model="form.introDetail" type="textarea" placeholder="产品尺寸,服务等" />
<el-input v-model="form.introDetail" type="textarea" placeholder="产品尺寸,服务等" maxlength="100" show-word-limit />
</el-form-item>
<div class="btnBox">
<el-form-item>
<el-button type="primary" @click="onSubmit">上架</el-button>
<el-button type="primary" @click="onSubmit" :disabled="saveBtn">保存</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetForm">重置</el-button>
</el-form-item>
</div>
</el-form>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted , inject} from 'vue';
import { ref, onMounted, inject, reactive } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import { ElMessage, type UploadFile , type UploadProps , genFileId , type UploadRawFile} from 'element-plus';
import { type UploadProps, genFileId, type UploadRawFile, type FormInstance, type FormRules } from 'element-plus';
import { SuccessInfo, WarnInfo, CommInfo } from '@/utils/messageInfo'; //ElMessage
import myAxios from "@/api/myAxios";
const fileSimple = ref() //
const uploadedFiles = ref<UploadFile[]>([]);//
const uploadedDescription = ref<UploadFile[]>([]);//
import { saveBtn, invInput } from '@/utils/entityProduct/globalVar';
import { validateName, validateIntro, validateDetail } from '@/utils/entityProduct/FormRules';
import { handleChange, handleRemove, form, Exceed_ProductImg } from '@/utils/entityProduct/picUpload';
const resetFormData = ref()
const form = ref({
name: '',
price: '', //
intro: '',//
festivalOrder: '',//
type: '',//
label: '',//
introDetail: '',//
goodImg: '', //url
detailImg: '', //url
inventory: '' //
})
//
const reload : any = inject("reload")
const typeList: any = ref([
{
value1: '',
label: ''
}
])
const uploadProductImg : any = ref() //ref
const uploadProductDetail : any = ref() //ref
const reload: any = inject("reload") //
const typeList: any = ref([])
const uploadProductImg: any = ref() //ref
const uploadProductDetail: any = ref() //ref
const labelList = ref([''])
const isqualify : any = ref(false)
const typeSelect : any = ref(false) //
onMounted(() => {
getTypeList() //select
})
const getTypeList = async () => { //
const res = await myAxios.post('/category/list', {}) //
for (let key in res.data.data) { //
typeList.value[key] = {
value1: res.data.data[key].typeName,
label: res.data.data[key].typeName
const res = await myAxios.post('/category/list/web', {}) //
for(let key in res.data.data) {
typeList.value.push(res.data.data[key].typeName)
}
}
}
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
console.log(uploadFile, uploadFiles)
console.log('typeList---->',typeList.value);
}
//
const onSubmit = async () => {
const values = Object.values(form.value);
const values = Object.values(form.value );
// 使some()
if (values.some(value => value === null || value === undefined || value === '')) {
ElMessage({
type:'warning',
message:'请检查表单数据是否完整填写'
})
if (values.some((value: any) => value === null || value === undefined || value === '' || value === 0)) {
WarnInfo('请检查表单数据是否完整填写')
return; //
}
const res = await myAxios.post('/goods/add', { ...form.value })
// console.log(res.data);
if (res.data.code === 1) {
ElMessage({
type: 'success',
message: "提交成功"
})
SuccessInfo('提交成功')
form.value = {} //12.18
reload() //
} else {
ElMessage.error("服务错误")
WarnInfo('服务错误')
return;
}
}
//
const handleChange = async (file: any, flag: number) => {
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",
// formDatafile
file: formData.get("file")
}
})
if (res.data.code === 1) {
// flag0 flag1
flag ? form.value.detailImg = res.data.data : form.value.goodImg = res.data.data
}
}
//
const loadForm = (value: any, flag: number) => {
flag ? form.value.type = value : form.value.festivalOrder = value // flag=1 "" flag=0
const loadForm = (value: any) => {
form.value.type = value // flag=1 "" flag=0
}
//
const resetForm = () =>{
const resetForm = () => {
resetFormData.value.resetFields()
}
const Exceed_ProductImg: UploadProps['onExceed'] = (files) => { //
uploadProductImg.value!.clearFiles()
const file = files[0] as UploadRawFile
file.uid = genFileId()
uploadProductImg.value!.handleStart(file)
}
const Exceed_ProductDetail: UploadProps['onExceed'] = (files) => { //
uploadProductDetail.value!.clearFiles()
uploadProductDetail.value!.clearFiles() //
const file = files[0] as UploadRawFile
file.uid = genFileId()
uploadProductDetail.value!.handleStart(file)
uploadProductDetail.value!.handleStart(file) //
}
const rules = reactive<FormRules<typeof form>>({ //
name: [{ validator: validateName, trigger: 'blur' }],
intro: [{ validator: validateIntro, trigger: 'blur' }],
introDetail: [{ validator: validateDetail, trigger: 'blur' }]
})
const addLabel = () => { //
if (labelList.value[labelList.value.length - 1] === '') {
WarnInfo('请填写完')
return;
}
if (labelList.value.length < 4) {
labelList.value.push('')
}
}
const addLabelList = () => { //
var string = ''
if (!labelList.value.some((item: any) => item === '')) {
string = labelList.value.join(';')
} else return;
form.value.label = string
}
const customTag = (e:any)=>{ //
if(e) {
form.value.inventory = 1
invInput.value = true
typeSelect.value = true
form.value.type = '定制'
} else {
form.value.inventory = 0
invInput.value = false
typeSelect.value = false
form.value.type = ''
}
}
</script>
<style scoped>
.totalBox {
display: flex;
margin: 0 auto;
}
.fromBox {
width: 700px;
height: 750px;
margin: 0 auto;
}
.NamePrice {
display: flex;
}
.IntroInven {
display: flex;
}
.festivalBox {
display: flex;
}
.btnBox {
display: flex;
justify-content: space-around;
}
</style>

View File

@ -2,20 +2,16 @@
<!-- 修改前请注释以前的 -->
<!-- 搜索 -->
<div>
<el-input style="width: 200px; height: 30px; margin-right: 10px;" suffix-icon="Search" placeholder="请输入商品名称"
<el-input style="width: 240px; margin-right: 10px;" suffix-icon="Search" placeholder="请输入商品名称"
v-model="productName"></el-input>
<el-form-item label="商品类型" style="width: 200px; margin-right: 10px;display: inline-block">
<el-select v-model="editForm.type" @change="(event: any) => searchByType(event)" placeholder="请选择">
<el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value1" />
<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-form-item>
<el-form-item label="商品状态" style="width: 200px;margin-right: 10px;display: inline-block">
<el-select v-model="state" placeholder="请选择" @change="(event: any) => searchByState(event)">
<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-form-item>
<el-button class="ml-5" type="primary" @click="onSearch(productName)" style="height: 25px;">搜索</el-button>
<el-button type="warning" @click="reset" style="height:25px">重置</el-button>
</div>
<div style="margin: 15px 0">
@ -41,12 +37,18 @@
<el-table-column prop="goodImg" label="商品图片">
<template #default="scope">
<div>
<img :src="scope.row.goodImg" alt="" style="height: 50px;">
<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"></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="商品状态">
@ -95,10 +97,8 @@
<el-input v-model="editForm.id" disabled></el-input>
</el-form-item>
<el-form-item label="商品图片">
<div v-if="editForm.goodImg">
<img :src="editForm.goodImg" alt="商品图标" class="thumbnail" style="width: 100px; height: 100px;" />
</div>
<el-upload
v-model:file-list="ImgArr"
ref="uploadProductImg"
action="#"
list-type="picture-card"
@ -107,7 +107,7 @@
:on-remove="handleRemove"
@change="(event: any) => handleChange(event, 0)"
:on-exceed="Exceed_ProductImg"
limit="1" >
limit="7" >
<el-icon>
<Plus/>
</el-icon>
@ -116,8 +116,9 @@
<el-form-item label="商品名称">
<el-input v-model="editForm.name"></el-input>
</el-form-item>
<el-form-item label="商品价格">
<el-input v-model="editForm.price"></el-input>
<el-form-item label="产品价格" prop="price">
<el-input-number v-model="editForm.price" min="0.01" :precision="2" :step="0.5" />
<p></p>
</el-form-item>
<el-form-item label="产品类别" prop="type">
<el-select v-model="editForm.type" @change="(event: any) => loadForm(event, 1)">
@ -175,9 +176,11 @@
</template>
<script setup lang="ts">
import { ElMessage , type UploadProps , genFileId ,type UploadRawFile } from 'element-plus';
import { ElMessage , type UploadProps , genFileId ,type UploadRawFile ,type UploadUserFile } from 'element-plus';
import { ref, onMounted, inject } from 'vue';
import myAxios from "@/api/myAxios";
import { handleChange, handleRemove, Exceed_ProductImg} from '@/utils/entityProduct/picUpload';
// import { handleChange, handleRemove, form, Exceed_ProductImg } from '@/utils/entityProduct/picUpload';
const total = ref(0); //
const idList = ref([]);
const searchParams: any = ref({ //
@ -186,14 +189,14 @@ const searchParams: any = ref({ //封装分页
sortField: "id", //ID
sortOrder: "descend" //
})
const fileSimple = ref()
const disabled = ref(true)
//
const title = ref('') //
const productName = ref('');
const DialogVisible = ref(false);
const state = ref(''); //select
const tableData : any= ref([]);
const editForm : any = ref({});
const tableData : any= ref([]); //
const editForm : any = ref({}); //
const reload : any = inject("reload") //
const uploadProductImg : any = ref() //ref
const uploadProductDetail : any = ref() //ref
@ -203,6 +206,7 @@ const typeList: any = ref([
label: ''
}
])
const ImgArr: any = ref<UploadUserFile[]>([]) //
onMounted(() => { //
getProductList()
getTypeList()
@ -210,7 +214,7 @@ onMounted(() => { //页面加载时获取商品列表和分类页表
const getProductList = async () => {
try {
const res = await myAxios.post('/goods/list/page', { ...searchParams.value });
// console.log(res.data)
console.log('res--->',res.data)
if (res.data.code === 1) {
tableData.value = res.data.data.records;
total.value = parseInt(res.data.data.total) //
@ -271,15 +275,20 @@ const deleteProduct = async (index: number) => {
}
getTypeList()
}
//--->
//
const ReviseOrView = (index: number, row: any , flag : number) => {
//flag disabled
ImgArr.value.splice(0,ImgArr.value.length)
var tempArr = row.goodImg.split(';')
tempArr.forEach((item: any)=>{
ImgArr.value.push({
url: item
})
})
flag ? (title.value = "编辑商品" , disabled.value = false) : (title.value = "商品详情" , disabled.value = true)
DialogVisible.value = true;
editForm.value = row;
};
//()
//
const handleOff = async (index: number, row: any) => {
row.isShelves ? row.isShelves = 0 : row.isShelves = 1 //
editForm.value = row;
@ -305,16 +314,6 @@ const handleCurrentChange = (Current: any) => {
const reset = () => {
reload()
};
// --
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
console.log(uploadFile, uploadFiles)
}
const Exceed_ProductImg: UploadProps['onExceed'] = (files , flag) => { //
uploadProductImg.value!.clearFiles()
const file = files[0] as UploadRawFile
file.uid = genFileId()
uploadProductImg.value!.handleStart(file)
}
const Exceed_ProductDetail: UploadProps['onExceed'] = (files) => { //
uploadProductDetail.value!.clearFiles()
const file = files[0] as UploadRawFile
@ -325,27 +324,6 @@ 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 handleChange = async (file: any, flag: number) => {
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") // formDatafile
}
})
if (res.data.code === 1) {
// flag0 flag1
flag ? editForm.value.detailImg = res.data.data : editForm.value.goodImg = res.data.data
}
}
const onSearch = (data : String)=>{ //
searchParams.value.name = data
searchParams.value.current = 1

View File

@ -89,7 +89,7 @@ onMounted(() => {
})
//
const getTypeList = async () => {
const res = await myAxios.post('/category/list')
const res = await myAxios.post('/category/list/web')
// console.log(res.data.data)
if (res.data.code === 1) {
tableData.value = res.data.data

View File

@ -193,22 +193,20 @@ const deliverGoods = async (row : any)=>{
getOrderList()
}
}
//
const deleteOrder = async (row : any) => {
// console.log(typeof index)
const res = await myAxios.post('/goods/delete', { id: row.id })
const deleteOrder = async (row : any) => { //+退
console.log('row-->',row.id)
const res = await myAxios.post('/wechat/refund/create', { id: row.id }) //退
console.log(res)
if (res.data.code === 1) {
ElMessage({
type: 'success',
message: '删除成功',
message: '退款成功',
})
getOrderList()
}
}
const reset = () => {
name.value = '';
};
const load = () => { }
//

View File

@ -17,7 +17,7 @@
</el-form-item>
</div>
<!-- 添加图文描述-->
<div class="boxPicture2">
<div>
<el-form-item label="添加课程展示图">
<el-upload ref="uploadProductDetail" action="#" list-type="picture-card" :auto-upload="false"
multiple="true" :on-change="(event: any) => handleChange(event, 1)" :on-exceed="Exceed_ProductDetail"
@ -60,7 +60,7 @@
</div>
</el-form>
</div>
<div class="timeTable">
<div>
<!-- <appointTime @time-Info="getInfo"></appointTime> -->
<calendarUtil @calendar-info="getInfo"></calendarUtil>
</div>

View File

@ -26,7 +26,7 @@
<!-- 数据展示 -->
<el-table :data="tableData" border stripe header-cell-class-name="headerBg"
:cell-style="{ 'text-align': 'center', 'font-size': '16px' }" @selection-change="handleSelectionChange"
:header-cell-style="{ 'text-align': 'center' }">
:header-cell-style="{ 'text-align': 'center' }" default-expand-all>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="课程编号" width="80">
<template #default="{ $index }">
@ -43,20 +43,31 @@
<el-table-column prop="name" label="课程名称"></el-table-column>
<el-table-column prop="price" label="单次价格" width="100"></el-table-column>
<el-table-column label="展开时间段" type="expand" width="80">
<template #default="{ $index,row }">
<template #default="{ $index }">
<!-- 放后端传来的预约时间 -->
<el-table :data="appointmentDateArr[$index]" :header-cell-style="{ 'text-align': 'center' }"
:cell-style="{ 'text-align': 'center' }">
<el-table-column label="是否可预约" prop="isAvailable" />
<el-table-column label="日期" prop="specificDate" />
<el-table-column label="操作">
<el-button size="small" @click="">
详情
<template v-slot="scope">
<el-button size="small" @click="updateDay(scope.row)">
<div v-if="scope.row.isAvailable == 1">取消预约</div>
<div v-if="scope.row.isAvailable == 0">启用预约</div>
</el-button>
<el-button size="small" @click="openDrawer">
<el-button size="small" type="primary" @click="">
添加日期
</el-button>
<el-button size="small" @click="openDrawer($index,scope.row)">
编辑
</el-button>
<el-button class="ml-5" type="danger">删除</el-button>
<el-popconfirm class="ml-5" confirm-button-text='确定' cancel-button-text='取消' icon="InfoFilled" icon-color="red"
title="是否确认删除" @confirm="deleteDate(scope.row.id)" width=180>
<template #reference>
<el-button class="ml-5" type="danger" v-if="tableData[$index].appointmentDateVOList.length>1">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</template>
@ -77,7 +88,7 @@
<el-button size="small" @click="ReviseOrView(scope.$index, scope.row, 1)">
编辑
</el-button>
<el-button size="small" @click="handleOff(scope.$index, scope.row)">
<el-button size="small" @click="handleOff(scope.row)">
<div v-if="scope.row.isShelves == 1">下架 </div>
<div v-if="scope.row.isShelves == 0">上架 </div>
</el-button>
@ -87,9 +98,6 @@
<el-button class="ml-5" type="danger">删除</el-button>
</template>
</el-popconfirm>
<el-popconfirm confirm-button-text='确定' cancel-button-text='取消' icon="el-icon-info" icon-color="red"
title="您确定删除吗?">
</el-popconfirm>
</template>
</el-table-column>
</el-table>
@ -124,21 +132,6 @@
<el-form-item label="商品价格">
<el-input v-model="editForm.price"></el-input>
</el-form-item>
<el-form-item label="商品数量">
<el-input v-model="editForm.inventory"></el-input>
</el-form-item>
<el-form-item label="商品状态">
<el-select v-model="editForm.isShelves">
<el-option label="上架" value="上架" />
<el-option label="下架" value="下架" />
</el-select>
</el-form-item>
<el-form-item label="是否为限定类产品" prop="festivalOrder">
<el-select v-model="editForm.festivalOrder" @change="(event: any) => loadForm(event, 0)">
<el-option label="是" value="1" />
<el-option label="否" value="0" />
</el-select>
</el-form-item>
<el-form-item label="商品标签">
<el-input v-model="editForm.label"></el-input>
</el-form-item>
@ -168,10 +161,38 @@
<!-- 时间段抽屉 -->
<el-drawer
v-model="drawer"
title="I am the title"
:title="'当前日期:'+drawerDate.specificDate + '&emsp;课程名称:' + className"
direction="ltr"
>
<span>Hi, there!</span>
@closed="closedDrawer">
<div style="margin-bottom: 20px;">选择当天时间段和人数</div>
<div v-for="(item,index) in drawerDate.timePeriodVOList">
<span>选择时间段</span>
<el-time-picker
v-model="timePickArr[index]"
format='HH:mm'
is-range="true"
range-separator="到"
start-placeholder="开始"
end-placeholder="结束"
value-format="HH:mm"
:style="{ width: '236px' }"
@change="saveTime(index)"
:disabled="timeAbleArr[index]"
/>
<div>
<span>最小人数:</span>
<el-select v-model="InfoArr[index].minNumber" style="width: 50px" @change="minNum(index)" :disabled="numAbleArr[index]">
<el-option v-for="item in minArr" :label="item" :value="item" />
</el-select>
<span>最大人数:</span>
<el-select v-model="InfoArr[index].maxNumber" style="width: 50px" @change="maxNum(index)" :disabled="numAbleArr[index]">
<el-option v-for="item in maxArr" :label="item" :value="item" />
</el-select>
<el-button type="primary" @click="UpdateNum(item,index)" v-if="timeAbleArr[index]">{{ btnText[index] }}</el-button>
<el-button type="danger" @click="subList(index)" v-if="index > 0">删除</el-button>
</div>
</div>
<el-button type="success" @click="addList">{{ addbtnText }}</el-button>
</el-drawer>
</template>
@ -180,7 +201,7 @@ import { ElMessage , type UploadProps , genFileId ,type UploadRawFile } from 'e
import { ref, onMounted, inject } from 'vue';
import myAxios from "@/api/myAxios";
const total = ref(0); //
const idList = ref([]);
const idList = ref([]); //
const searchParams: any = ref({ //
current: 1, //
pageSize: 5, //
@ -199,9 +220,29 @@ const reload : any = inject("reload") //页面重新刷新
const fileSimple = ref()
const uploadProductImg : any = ref() //ref
const uploadProductDetail : any = ref() //ref
const drawer = ref(false)
//
const drawer = ref(false) //
const drawerDate : any = ref({}) //
const timePickArr : any = ref([]) //
const minArr : any = ref([]) //
const maxArr : any = ref([]) //
const InfoArr : any = ref([]) //
const btnText = ref(Array.from({length:15},()=>('修改')))
const addbtnText = ref('添加时间段')
const timeAbleArr = ref( //
Array.from({ length: 15 },()=>(false))
)
const numAbleArr = ref( //
Array.from({ length: 15 },()=>(true))
)
const className = ref('') //
const nowBookPeo = ref(0) //
onMounted(() => { //
getProductList()
for(let i = 0;i <=50 ; i++) { //
minArr.value[i] = 5+i
maxArr.value[i] = 6+i
}
})
const getProductList = async () => {
try {
@ -211,7 +252,7 @@ const getProductList = async () => {
tableData.value = res.data.data.records;
total.value = parseInt(res.data.data.total) //
appointmentDateArr.value.splice(0,total.value)
console.log(tableData.value);
console.log('tableData--->',tableData.value);
tableData.value.forEach((val : any) => {
appointmentDateArr.value.push(val.appointmentDateVOList)
})
@ -229,6 +270,20 @@ const getProductList = async () => {
}
}
const saveEdit = async () => { //
const res = await myAxios.post('/goods/service/single/update',{...editForm.value})
if(res.data.code === 1) {
DialogVisible.value = false
ElMessage({
type: 'success',
message: '更新成功'
})
} else {
ElMessage({
type: 'error',
message: '请检查字段是否正确填写'
})
}
console.log(res.data);
}
const searchByState = (event : any) => { ///
searchParams.value.isShelves = event
@ -238,7 +293,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/service', { id: index })
console.log(res)
if (res.data.code === 1) {
ElMessage({
@ -248,7 +303,6 @@ const deleteProduct = async (index: number) => {
getProductList()
}
}
//--->
//
const ReviseOrView = (index: number, row: any , flag : number) => {
//flag disabled
@ -257,16 +311,16 @@ const ReviseOrView = (index: number, row: any , flag : number) => {
editForm.value = row;
};
//()
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})
const handleOff = async (row: any) => {
console.log(row.isShelves);
const res = await myAxios.post('/goods/service/shelves',{id: row.id})
if(res.data.code === 1) {
ElMessage({
type:'success',
message:'更新成功'
})
}
getProductList()
}
//
const handleSizeChange = (newSize: any) => {
@ -298,10 +352,6 @@ const Exceed_ProductDetail: UploadProps['onExceed'] = (files) => { //覆盖商
file.uid = genFileId()
uploadProductDetail.value!.handleStart(file)
}
// //
const loadForm = (value: any, flag: number) => {
flag ? editForm.value.type = value : editForm.value.festivalOrder = value // flag=1 "" flag=0
}
//
const handleChange = async (file: any, flag: number) => {
fileSimple.value = file
@ -346,9 +396,147 @@ const delBatch = async ()=>{
}
}
const handleSelectionChange =()=>{}
const openDrawer =()=>{
const openDrawer =(index : number,dateInfo : any)=>{ //
// console.log('row-->',dateInfo);
className.value = tableData.value[index].name
timePickArr.value.splice(0,timePickArr.value.length) //
drawerDate.value = dateInfo
InfoArr.value = dateInfo.timePeriodVOList
console.log(drawerDate.value);
dateInfo.timePeriodVOList.forEach((item:any,index:number)=>{ //
let arr = item.timeSlot.split("-")
timeAbleArr.value[index] = true
timePickArr.value.push(arr)
})
drawer.value = true
}
const saveTime =(index: number)=>{
try{
drawerDate.value.timePeriodVOList[index].timeSlot = timePickArr.value[index][0]+'-'+timePickArr.value[index][1]
} catch {
drawerDate.value.timePeriodVOList[index].timeSlot = ''
}
}
const minNum =(index: number)=>{}
const maxNum =(index: number)=>{}
const addList = async ()=>{
let newIndex = drawerDate.value.timePeriodVOList.length
numAbleArr.value[newIndex] = false //
console.log('drawerDate--->',drawerDate.value);
if(addbtnText.value === '添加时间段') {
drawerDate.value.timePeriodVOList.push({ //
id: 0,
timeSlot: '',
maxNumber: 0,
minNumber: 0
})
timePickArr.value.push([])
addbtnText.value = '保存时间段'
}
// console.log('timeSlot-->',drawerDate.value.timePeriodVOList[newIndex].timeSlot);
if(!judgeNull(drawerDate.value.timePeriodVOList)) {
ElMessage({
type: 'warning',
message: '填写时间段和人数'
})
return;
}
const res = await myAxios.post('/appointmentDate/add/time',{
timeSlot: drawerDate.value.timePeriodVOList[newIndex-1].timeSlot,
minNumber: drawerDate.value.timePeriodVOList[newIndex-1].minNumber,
maxNumber: drawerDate.value.timePeriodVOList[newIndex-1].maxNumber,
appointmentDateId: drawerDate.value.id,
})
console.log(res.data.data);
if(res.data.code === 1) {
drawerDate.value.timePeriodVOList[newIndex-1].id = res.data.data
drawerDate.value.timePeriodVOList.forEach((item: any,index: number)=>{
timeAbleArr.value[index] = true
numAbleArr.value[index] = true
})
ElMessage({
type: 'success',
message: '添加时间段成功'
})
} else {
ElMessage({
type: 'error',
message: '添加失败'
})
}
console.log(res.data);
addbtnText.value = '添加时间段'
}
const subList =(index: number)=>{}
const UpdateNum = async (item: any,index:number)=>{ //
btnText.value[index] === '修改' ? btnText.value[index] = '保存' : btnText.value[index] = '修改'
btnText.value[index] === '保存' ? numAbleArr.value[index] = false : numAbleArr.value[index] = true
if(btnText.value[index] === '修改') {
const res = await myAxios.post('/appointmentDate/update/time',{
id: item.id,
minNumber: item.minNumber,
maxNumber: item.maxNumber
})
if(res.data.code === 1) {
ElMessage({
type: 'success',
message: '更新成功'
})
} else {
ElMessage({
type: 'error',
message: '更新失败'
})
}
}
}
const updateDay = async (row:any)=>{ //
const res = await myAxios.post('/appointmentDate/update/status',{id: row.id})
if(res.data.code === 1) {
ElMessage({
type:'success',
message: '修改成功'
});
}
getProductList()
}
const judgeNull =(List : any)=>{ //
console.log('List--->',List);
if (List.some((item:any) => item.timeSlot=== '' || item.minNumber === 0 || item.maxNumber === 0)) {
return false;
}
return true;
}
const closedDrawer =()=>{ //
let newIndex = drawerDate.value.timePeriodVOList.length
timeAbleArr.value.forEach((item: any ,index: number)=>{
timeAbleArr.value[index] = false
numAbleArr.value[index] = true
btnText.value[index] = '修改'
})
if(!judgeNull(drawerDate.value.timePeriodVOList)) {
console.log('关闭抽屉的删除数组被激活');
drawerDate.value.timePeriodVOList.splice(newIndex-1,1)
}
addbtnText.value = '添加时间段'
}
const deleteDate = async (id: number)=>{ //
console.log(id)
const res = await myAxios.post('/appointmentDate/del/id',{id:id})
// console.log('res--->',res);
if(res.data.code === 1) {
getProductList()
ElMessage({
type: 'success',
message: '删除成功'
})
} else {
ElMessage({
type: 'info',
message: '请求失败'
})
}
}
</script>
<style scoped>

View File

@ -0,0 +1,69 @@
<template>
<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-dialog v-model="dialogVisible">
<img w-full :src="dialogImageUrl" alt="Preview Image" />
</el-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { Plus } from '@element-plus/icons-vue'
import type { UploadProps, UploadUserFile } from 'element-plus'
const fileList = ref<UploadUserFile[]>([
{
name: 'food.jpeg',
url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100',
},
{
name: 'plant-1.png',
url: '/images/plant-1.png',
},
{
name: 'food.jpeg',
url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100',
},
{
name: 'plant-2.png',
url: '/images/plant-2.png',
},
{
name: 'food.jpeg',
url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100',
},
{
name: 'figure-1.png',
url: '/images/figure-1.png',
},
{
name: 'food.jpeg',
url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100',
},
{
name: 'figure-2.png',
url: '/images/figure-2.png',
},
])
const dialogImageUrl = ref('')
const dialogVisible = ref(false)
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
console.log(uploadFile, uploadFiles)
}
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
dialogImageUrl.value = uploadFile.url!
dialogVisible.value = true
}
</script>