Browse Source

update:更新一些页面

RuHu.Xu 1 year ago
parent
commit
71f733046f

+ 1 - 1
.vscode/settings.json

@@ -86,7 +86,7 @@
     "source.fixAll.eslint": "explicit"
   },
   "[vue]": {
-    "editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
+    "editor.defaultFormatter": "Vue.volar"
   },
   "i18n-ally.localesPaths": ["src/locales"],
   "i18n-ally.keystyle": "nested",

+ 3 - 2
index.html

@@ -1,10 +1,11 @@
 <!DOCTYPE html>
-<html lang="en">
+<html lang="en" style="font-size: 16px;">
   <head>
     <meta charset="UTF-8" />
     <link rel="icon" href="/favicon.ico" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0" /> -->
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
     <meta
       name="keywords"
       content="中星管理系统 基于 vue3 + CompositionAPI + typescript + vite3 + element plus 的后台开源免费管理系统!"

+ 64 - 0
src/api/system/sale/merchant/index.ts

@@ -0,0 +1,64 @@
+import request from '@/config/axios'
+
+// 商户 VO
+export interface MerchantVO {
+  // 商户id
+  id: number
+  // 商户名称
+  name: string
+  // 商户状态,关联商户状态表
+  status: number
+  // 简介
+  description: string
+  // 负责人
+  contact: string
+  // 所在地
+  address: string
+  // 负责人电话
+  contactNumber: string
+  // 官网
+  website: string
+  // 维权电话
+  complaintsHotline: string
+  // 客服电话
+  customerServiceHotline: string
+  // 邮箱
+  email: string
+  // 营业执照图片路径
+  businessLicensePicture: string
+  // 服务到期时间
+  expireTime: Date
+}
+
+// 商户 API
+export const MerchantApi = {
+  // 查询商户分页
+  getMerchantPage: async (params: any) => {
+    return await request.get({ url: `/sale/merchant/page`, params })
+  },
+
+  // 查询商户详情
+  getMerchant: async (id: number) => {
+    return await request.get({ url: `/sale/merchant/get?id=` + id })
+  },
+
+  // 新增商户
+  createMerchant: async (data: MerchantVO) => {
+    return await request.post({ url: `/sale/merchant/create`, data })
+  },
+
+  // 修改商户
+  updateMerchant: async (data: MerchantVO) => {
+    return await request.put({ url: `/sale/merchant/update`, data })
+  },
+
+  // 删除商户
+  deleteMerchant: async (id: number) => {
+    return await request.delete({ url: `/sale/merchant/delete?id=` + id })
+  },
+
+  // 导出商户 Excel
+  exportMerchant: async (params) => {
+    return await request.download({ url: `/sale/merchant/export-excel`, params })
+  }
+}

+ 46 - 0
src/api/system/sale/shop/index.ts

@@ -0,0 +1,46 @@
+import request from '@/config/axios'
+
+// 店铺 VO
+export interface ShopVO {
+  // 店铺id
+  id: number
+  // 店铺名称
+  name: string
+  // 店铺状态
+  status: number
+  // 商户id
+  merchantId: number
+}
+
+// 店铺 API
+export const ShopApi = {
+  // 查询店铺分页
+  getShopPage: async (params: any) => {
+    return await request.get({ url: `/sale/shop/page`, params })
+  },
+
+  // 查询店铺详情
+  getShop: async (id: number) => {
+    return await request.get({ url: `/sale/shop/get?id=` + id })
+  },
+
+  // 新增店铺
+  createShop: async (data: ShopVO) => {
+    return await request.post({ url: `/sale/shop/create`, data })
+  },
+
+  // 修改店铺
+  updateShop: async (data: ShopVO) => {
+    return await request.put({ url: `/sale/shop/update`, data })
+  },
+
+  // 删除店铺
+  deleteShop: async (id: number) => {
+    return await request.delete({ url: `/sale/shop/delete?id=` + id })
+  },
+
+  // 导出店铺 Excel
+  exportShop: async (params) => {
+    return await request.download({ url: `/sale/shop/export-excel`, params })
+  }
+}

+ 42 - 0
src/api/system/sale/shopstatus/index.ts

@@ -0,0 +1,42 @@
+import request from '@/config/axios'
+
+// 店铺状态 VO
+export interface ShopStatusVO {
+  // id
+  id: number
+  // 名称
+  name: string
+}
+
+// 店铺状态 API
+export const ShopStatusApi = {
+  // 查询店铺状态分页
+  getShopStatusPage: async (params: any) => {
+    return await request.get({ url: `/sale/shop-status/page`, params })
+  },
+
+  // 查询店铺状态详情
+  getShopStatus: async (id: number) => {
+    return await request.get({ url: `/sale/shop-status/get?id=` + id })
+  },
+
+  // 新增店铺状态
+  createShopStatus: async (data: ShopStatusVO) => {
+    return await request.post({ url: `/sale/shop-status/create`, data })
+  },
+
+  // 修改店铺状态
+  updateShopStatus: async (data: ShopStatusVO) => {
+    return await request.put({ url: `/sale/shop-status/update`, data })
+  },
+
+  // 删除店铺状态
+  deleteShopStatus: async (id: number) => {
+    return await request.delete({ url: `/sale/shop-status/delete?id=` + id })
+  },
+
+  // 导出店铺状态 Excel
+  exportShopStatus: async (params) => {
+    return await request.download({ url: `/sale/shop-status/export-excel`, params })
+  }
+}

+ 1 - 1
src/layout/components/AppView.vue

@@ -35,7 +35,7 @@
 
 <template>
 	<section :class="[
-      'p-[var(--app-content-padding)] w-[calc(100%-var(--app-content-padding)-var(--app-content-padding))] bg-[var(--app-content-bg-color)] dark:bg-[var(--el-bg-color)]',
+      'p-[var(--app-content-padding)] w-[calc(100%-var(--app-content-padding)-var(--app-content-padding))] bg-[var(--el-color-white)] dark:bg-[var(--el-bg-color)]',
       {
         '!min-h-[calc(100%-var(--app-content-padding)-var(--app-content-padding)-var(--app-footer-height))]':
           (fixedHeader &&

+ 1 - 0
src/layout/components/UserInfo/src/UserInfo.vue

@@ -44,6 +44,7 @@ const loginOut = () => {
 }
 const toProfile = async () => {
   push('/user/profile')
+  
 }
 const toDocument = () => {
   window.open('https://doc.iocoder.cn/')

+ 8 - 2
src/views/Profile/Index.vue

@@ -8,7 +8,7 @@
       </template>
       <ProfileUser />
     </el-card>
-    <el-card class="user ml-3 w-2/3" shadow="hover">
+     <el-card class="user ml-3 w-2/3" shadow="hover">
       <template #header>
         <div class="card-header">
           <span>{{ t('profile.info.title') }}</span>
@@ -29,13 +29,19 @@
       </div>
     </el-card>
   </div>
+  
 </template>
 <script lang="ts" setup>
 import { BasicInfo, ProfileUser, ResetPwd, UserSocial } from './components'
-
+const dialogVisible = ref(false) // 弹窗的是否展示
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
 const { t } = useI18n()
 defineOptions({ name: 'Profile' })
 const activeName = ref('basicInfo')
+/** 打开弹窗 */
+const open = async () => {
+  dialogVisible.value = true
+}
 </script>
 <style scoped>
 .user {

+ 1 - 1
src/views/mall/product/spu/form/DescriptionForm.vue

@@ -2,7 +2,7 @@
 <template>
   <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" :disabled="isDetail">
     <!--富文本编辑器组件-->
-    <el-form-item label="商品详情" prop="description">
+    <el-form-item prop="description">
       <Editor v-model:modelValue="formData.description" />
     </el-form-item>
   </el-form>

+ 9 - 6
src/views/mall/product/spu/form/index.vue

@@ -24,10 +24,13 @@
 			<div class="left">
 				<SPuUploadImg v-model="formData.picUrl" :disabled="isDetail" />
 				<el-tabs v-model="activeName" tab-position="left" class="child-tabs">
-					<el-tab-pane label="基础设置" name="info" />
-					<el-tab-pane label="价格库存" name="sku" />
+					<el-tab-pane label="基本信息" name="info" />
+					<el-tab-pane label="价格/规格/型号" name="sku" />
+					<el-tab-pane label="详情" name="description" />
+					<el-tab-pane label="评价" name="comment" />
+					<el-tab-pane label="客服" name="service" />
+					<el-tab-pane label="售后" name="aftersale" />
 					<el-tab-pane label="物流设置" name="delivery" />
-					<el-tab-pane label="商品详情" name="description" />
 					<el-tab-pane label="其它设置" name="other" />
 				</el-tabs>
 			</div>
@@ -188,9 +191,9 @@
 	const openType = ref("")
 	const parentNewStatus = ref(0)
 	const isFullScreen = ref(false)
-	const handleError = (e) => {
-		e.target.src = "https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"
-	}
+	// const handleError = (e) => {
+	// 	e.target.src = "https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"
+	// }
 	/** 打开弹窗 */
 	const open = async (type : string, row : any, newStatus : number, tabType : number) => {
 

+ 346 - 337
src/views/mall/product/spu/index.vue

@@ -1,72 +1,77 @@
 <!-- 商品中心 - 商品列表  -->
+
 <template>
 	<!-- 列表 -->
 	<ContentWrap style="" class="spu-div">
-		<div style="position: relative;">
-			<div style="text-align: right;background: #fafbfc;padding: 10px;">
+
+		<div style="display: flex;justify-content: space-between;align-items: center;padding: 0 10px;">
+			<el-tabs v-model="queryParams.tabType" @tab-click="handleTabClick" class="parent-tabs">
+				<el-tab-pane v-for="item in tabsData" :key="item.type" :label="item.name + '(' + item.count + ')'"
+					:name="item.type" />
+			</el-tabs>
+			<div style="text-align: right;padding: 10px;">
 				<el-input v-model="queryParams.name" class="!w-240px" placeholder="搜索商品名称" @keyup.enter="handleQuery">
 					<template #suffix>
 						<el-icon class="el-input__icon" @click="handleQuery" style="cursor: pointer;">
 							<Search />
 						</el-icon>
 					</template>
+
 					<template #append>
 						<el-button :icon="Operation" @click="showSearchMore" />
 					</template>
 				</el-input>
 				&nbsp;
-				<el-button v-hasPermi="['product:spu:create']" @click="openForm('create','',0)">
+				<el-button v-hasPermi="['product:spu:create']" @click="openForm('create', '', 0)">
 					<Icon class="mr-5px" icon="ep:plus" />
 					新增
 				</el-button>
 			</div>
-			<div class="searchMore" v-if="searchMoreShow">
-				<el-form ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px" label-width="68px">
-					<div>
-						<el-form-item label="商品分类" prop="categoryId">
-							<el-cascader v-model="queryParams.categoryId" :options="categoryList" :props="defaultProps"
-								class="w-1/1" clearable filterable placeholder="请选择商品分类" />
-						</el-form-item>
-						<el-form-item label="创建时间" prop="createTime">
-							<el-date-picker style="margin-right: unset;" v-model="queryParams.createTime"
-								:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px"
-								end-placeholder="结束日期" start-placeholder="开始日期" type="daterange"
-								value-format="YYYY-MM-DD HH:mm:ss" />
-						</el-form-item>
-					</div>
-					<div>
-						<el-button @click="hideSearchMore">
-							收起
-						</el-button>
-						<el-button @click="resetQuery">
-							重置
-						</el-button>
-						<el-button @click="handleQuery" plain type="primary">
-							<Icon class="mr-5px" icon="ep:search" />
-							搜索
-						</el-button>
-						<!-- <el-button v-hasPermi="['product:spu:export']" :loading="exportLoading" plain type="success"
+
+		</div>
+		<div class="searchMore" v-if="searchMoreShow">
+			<el-form ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px" label-width="68px">
+				<div>
+					<el-form-item label="商品分类" prop="categoryId">
+						<el-cascader v-model="queryParams.categoryId" :options="categoryList" :props="defaultProps" class="w-1/1"
+							clearable filterable placeholder="请选择商品分类" />
+					</el-form-item>
+					<el-form-item label="创建时间" prop="createTime">
+						<el-date-picker style="margin-right: unset;" v-model="queryParams.createTime"
+							:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" end-placeholder="结束日期"
+							start-placeholder="开始日期" type="daterange" value-format="YYYY-MM-DD HH:mm:ss" />
+					</el-form-item>
+				</div>
+				<div>
+					<el-button @click="hideSearchMore">
+						收起
+					</el-button>
+					<el-button @click="resetQuery">
+						重置
+					</el-button>
+					<el-button @click="handleQuery" plain type="primary">
+						<Icon class="mr-5px" icon="ep:search" />
+						搜索
+					</el-button>
+					<!-- <el-button v-hasPermi="['product:spu:export']" :loading="exportLoading" plain type="success"
 								@click="handleExport">
 								<Icon class="mr-5px" icon="ep:download" />
 								导出
 							</el-button> -->
-					</div>
-				</el-form>
-			</div>
+				</div>
+			</el-form>
 		</div>
-		<el-tabs v-model="queryParams.tabType" @tab-click="handleTabClick" class="parent-tabs">
-			<el-tab-pane v-for="item in tabsData" :key="item.type" :label="item.name + '(' + item.count + ')'"
-				:name="item.type" />
-		</el-tabs>
+
+
 		<el-row>
-			<el-col v-for="(o, index) in list" class="product-card" :key="index" :span="7"
-				@mouseover="handleMouseOver(index)" @mouseout="handleMouseOut(index)">
-				<el-card @click="openDetail('view',o,ProductSpuStatusEnum.RECYCLE.status,queryParams.tabType)">
+			<el-col v-for="(o, index) in list" class="product-card" :key="index" :span="7" @mouseover="handleMouseOver(index)"
+				@mouseout="handleMouseOut(index)">
+				<el-card @click="openDetail('view', o, ProductSpuStatusEnum.RECYCLE.status, queryParams.tabType)">
 					<div style="display: flex;justify-content: space-between;align-items: center;margin-bottom: 5px;">
 						<p style="width: 100%;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;font-size: 16px;color:#000"
-							:title="o.name">{{o.name}}
+							:title="o.name">{{ o.name }}
 						</p>
-						<div @click.stop="openForm('update',o,ProductSpuStatusEnum.RECYCLE.status,queryParams.tabType)"
+						<div @click.stop="openForm('update', o, ProductSpuStatusEnum.RECYCLE.status, queryParams.tabType)"
 							v-show="o.showSetting" class="setting">
 							<el-icon size="20" color="rgb(220 223 231)">
 								<Setting />
@@ -76,16 +81,17 @@
 
 					</div>
 					<div style="display:flex;align-items: center;">
-						<div style="width: 178px;height: 100px;margin-right:10px;border:1px solid rgb(220 223 231);border-radius: 5px;display: flex;align-items: center;justify-content: center;"
+						<div
+							style="width: 178px;height: 100px;margin-right:10px;border:1px solid rgb(220 223 231);border-radius: 5px;display: flex;align-items: center;justify-content: center;"
 							@error="handleError">
 							<img :src="o.picUrl" style="width: auto;height: auto;max-width: 100%;max-height: 100%;" />
 						</div>
 
 						<div style='line-height: 25px;'>
 							<p>¥{{ fenToYuan(o.price) }}</p>
-							<p>销量:{{o.salesCount}}</p>
-							<p>库存:{{o.stock}}</p>
-							<p>状态:{{o.status == 1?"上架":"下架"}}</p>
+							<p>销量:{{ o.salesCount }}</p>
+							<p>库存:{{ o.stock }}</p>
+							<p>状态:{{ o.status == 1 ? "上架" : "下架" }}</p>
 						</div>
 					</div>
 				</el-card>
@@ -94,7 +100,7 @@
 		<div v-if="list.length == 0">
 			<p style="text-align: center;margin-top: 100px;">暂无商品</p>
 		</div>
-		
+
 
 		<!-- 分页 -->
 		<Pagination v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNo" :total="total"
@@ -103,329 +109,332 @@
 		<SpuIndex ref="formRef" @success="getList" />
 	</ContentWrap>
 </template>
+
 <script lang="ts" setup>
-	import { TabsPaneContext } from 'element-plus'
-	import { Setting, Search, Operation } from '@element-plus/icons-vue'
-	import { createImageViewer } from '@/components/ImageViewer'
-	import { dateFormatter } from '@/utils/formatTime'
-	import { defaultProps, handleTree, treeToString } from '@/utils/tree'
-	import { ProductSpuStatusEnum } from '@/utils/constants'
-	import { fenToYuan } from '@/utils'
-	import download from '@/utils/download'
-	import * as ProductSpuApi from '@/api/mall/product/spu'
-	import * as ProductCategoryApi from '@/api/mall/product/category'
-	import SpuIndex from "./form/index.vue"
-
-	defineOptions({ name: 'ProductSpu' })
-
-	const message = useMessage() // 消息弹窗
-	const { t } = useI18n() // 国际化
-	const { push } = useRouter() // 路由跳转
-
-	const loading = ref(false) // 列表的加载中
-	const exportLoading = ref(false) // 导出的加载中
-	const total = ref(0) // 列表的总页数
-	const list = ref<ProductSpuApi.Spu[]>([]) // 列表的数据
-	// tabs 数据
-	const tabsData = ref([
-		{
-			name: '出售中',
-			type: 0,
-			count: 0
-		},
-		{
-			name: '仓库中',
-			type: 1,
-			count: 0
-		},
-		{
-			name: '已售罄',
-			type: 2,
-			count: 0
-		},
-		{
-			name: '警戒库存',
-			type: 3,
-			count: 0
-		},
-		{
-			name: '回收站',
-			type: 4,
-			count: 0
-		}
-	])
-
-	const queryParams = ref({
-		pageNo: 1,
-		pageSize: 10,
-		tabType: 0,
-		name: '',
-		categoryId: undefined,
-		createTime: undefined
-	}) // 查询参数
-	const queryFormRef = ref() // 搜索的表单Ref
-	const searchMoreShow = ref(false)
-	// 鼠标移入显示变动图标
-	function handleMouseOver(index) {
-		list.value[index].showSetting = true;
-	}
-	// 鼠标移出不显示图标
-	function handleMouseOut(index) {
-		list.value[index].showSetting = false;
-	}
-	// 裂图替换
-	const handleError = (e) => {
-		e.target.src = "https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"
+import { TabsPaneContext } from 'element-plus'
+import { Setting, Search, Operation } from '@element-plus/icons-vue'
+import { createImageViewer } from '@/components/ImageViewer'
+import { dateFormatter } from '@/utils/formatTime'
+import { defaultProps, handleTree, treeToString } from '@/utils/tree'
+import { ProductSpuStatusEnum } from '@/utils/constants'
+import { fenToYuan } from '@/utils'
+import download from '@/utils/download'
+import * as ProductSpuApi from '@/api/mall/product/spu'
+import * as ProductCategoryApi from '@/api/mall/product/category'
+import SpuIndex from "./form/index.vue"
+
+defineOptions({ name: 'ProductSpu' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const { push } = useRouter() // 路由跳转
+
+const loading = ref(false) // 列表的加载中
+const exportLoading = ref(false) // 导出的加载中
+const total = ref(0) // 列表的总页数
+const list = ref<ProductSpuApi.Spu[]>([]) // 列表的数据
+// tabs 数据
+const tabsData = ref([
+	{
+		name: '出售中',
+		type: 0,
+		count: 0
+	},
+	{
+		name: '仓库中',
+		type: 1,
+		count: 0
+	},
+	{
+		name: '已售罄',
+		type: 2,
+		count: 0
+	},
+	{
+		name: '警戒库存',
+		type: 3,
+		count: 0
+	},
+	{
+		name: '回收站',
+		type: 4,
+		count: 0
 	}
-	// 打开更多搜索条件
-	const showSearchMore = () => {
-		searchMoreShow.value = !searchMoreShow.value
-	}
-	const hideSearchMore = () => {
+])
+
+const queryParams = ref({
+	pageNo: 1,
+	pageSize: 10,
+	tabType: 0,
+	name: '',
+	categoryId: undefined,
+	createTime: undefined
+}) // 查询参数
+const queryFormRef = ref() // 搜索的表单Ref
+const searchMoreShow = ref(false)
+// 鼠标移入显示变动图标
+function handleMouseOver(index) {
+	list.value[index].showSetting = true;
+}
+// 鼠标移出不显示图标
+function handleMouseOut(index) {
+	list.value[index].showSetting = false;
+}
+// 裂图替换
+const handleError = (e) => {
+	e.target.src = "https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg"
+}
+// 打开更多搜索条件
+const showSearchMore = () => {
+	searchMoreShow.value = !searchMoreShow.value
+}
+const hideSearchMore = () => {
+	searchMoreShow.value = false
+}
+
+/** 查询列表 */
+const getList = async () => {
+	loading.value = true
+	try {
+		const data = await ProductSpuApi.getSpuPage(queryParams.value)
+		data.list.forEach(obj => {
+			obj.showSetting = false;
+		});
+
+		list.value = data.list
+		// console.log(list.value)
+		total.value = data.total
+
+	} finally {
+		loading.value = false
 		searchMoreShow.value = false
-	}
-
-	/** 查询列表 */
-	const getList = async () => {
-		loading.value = true
-		try {
-			const data = await ProductSpuApi.getSpuPage(queryParams.value)
-			data.list.forEach(obj => {
-				obj.showSetting = false;
-			});
-
-			list.value = data.list
-			// console.log(list.value)
-			total.value = data.total
+		getTabsCount()
 
-		} finally {
-			loading.value = false
-			searchMoreShow.value = false
-			getTabsCount()
-
-		}
 	}
-
-	/** 切换 Tab */
-	const handleTabClick = (tab : TabsPaneContext) => {
-		queryParams.value.tabType = tab.paneName as number
-		getList()
+}
+
+/** 切换 Tab */
+const handleTabClick = (tab: TabsPaneContext) => {
+	queryParams.value.tabType = tab.paneName as number
+	getList()
+}
+
+/** 获得每个 Tab 的数量 */
+const getTabsCount = async () => {
+	const res = await ProductSpuApi.getTabsCount()
+	for (let objName in res) {
+		tabsData.value[Number(objName)].count = res[objName]
 	}
-
-	/** 获得每个 Tab 的数量 */
-	const getTabsCount = async () => {
-		const res = await ProductSpuApi.getTabsCount()
-		for (let objName in res) {
-			tabsData.value[Number(objName)].count = res[objName]
-		}
-	}
-
-	/** 添加到仓库 / 回收站的状态 */
-	const handleStatus02Change = async (row : any, newStatus : number) => {
-		try {
-			// 二次确认
-			const text = newStatus === ProductSpuStatusEnum.RECYCLE.status ? '加入到回收站' : '恢复到仓库'
-			await message.confirm(`确认要"${row.name}"${text}吗?`)
-			// 发起修改
-			await ProductSpuApi.updateStatus({ id: row.id, status: newStatus })
-			message.success(text + '成功')
-			// 刷新 tabs 数据
-			await getTabsCount()
-			// 刷新列表
-			await getList()
-		} catch { }
-	}
-
-	/** 更新上架/下架状态 */
-	const handleStatusChange = async (row : any) => {
-		try {
-			// 二次确认
-			const text = row.status ? '上架' : '下架'
-			await message.confirm(`确认要${text}"${row.name}"吗?`)
-			// 发起修改
-			await ProductSpuApi.updateStatus({ id: row.id, status: row.status })
-			message.success(text + '成功')
-			// 刷新 tabs 数据
-			await getTabsCount()
-			// 刷新列表
-			await getList()
-		} catch {
-			// 异常时,需要重置回之前的值
-			row.status =
-				row.status === ProductSpuStatusEnum.DISABLE.status
-					? ProductSpuStatusEnum.ENABLE.status
-					: ProductSpuStatusEnum.DISABLE.status
-		}
+}
+
+/** 添加到仓库 / 回收站的状态 */
+const handleStatus02Change = async (row: any, newStatus: number) => {
+	try {
+		// 二次确认
+		const text = newStatus === ProductSpuStatusEnum.RECYCLE.status ? '加入到回收站' : '恢复到仓库'
+		await message.confirm(`确认要"${row.name}"${text}吗?`)
+		// 发起修改
+		await ProductSpuApi.updateStatus({ id: row.id, status: newStatus })
+		message.success(text + '成功')
+		// 刷新 tabs 数据
+		await getTabsCount()
+		// 刷新列表
+		await getList()
+	} catch { }
+}
+
+/** 更新上架/下架状态 */
+const handleStatusChange = async (row: any) => {
+	try {
+		// 二次确认
+		const text = row.status ? '上架' : '下架'
+		await message.confirm(`确认要${text}"${row.name}"吗?`)
+		// 发起修改
+		await ProductSpuApi.updateStatus({ id: row.id, status: row.status })
+		message.success(text + '成功')
+		// 刷新 tabs 数据
+		await getTabsCount()
+		// 刷新列表
+		await getList()
+	} catch {
+		// 异常时,需要重置回之前的值
+		row.status =
+			row.status === ProductSpuStatusEnum.DISABLE.status
+				? ProductSpuStatusEnum.ENABLE.status
+				: ProductSpuStatusEnum.DISABLE.status
 	}
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+	try {
+		// 删除的二次确认
+		await message.delConfirm()
+		// 发起删除
+		await ProductSpuApi.deleteSpu(id)
+		message.success(t('common.delSuccess'))
+		// 刷新tabs数据
+		await getTabsCount()
+		// 刷新列表
+		await getList()
+	} catch { }
+}
 
-	/** 删除按钮操作 */
-	const handleDelete = async (id : number) => {
-		try {
-			// 删除的二次确认
-			await message.delConfirm()
-			// 发起删除
-			await ProductSpuApi.deleteSpu(id)
-			message.success(t('common.delSuccess'))
-			// 刷新tabs数据
-			await getTabsCount()
-			// 刷新列表
-			await getList()
-		} catch { }
+/** 商品图预览 */
+const imagePreview = (imgUrl: string) => {
+	createImageViewer({
+		urlList: [imgUrl]
+	})
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+	getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+	queryParams.value.categoryId = undefined
+	queryParams.value.createTime = undefined
+	queryParams.value.name = ""
+	// queryFormRef.value.resetFields()
+	// console.log(queryParams.value)
+	// console.log(queryFormRef.value)
+	handleQuery()
+}
+
+const formRef = ref()
+/** 新增或修改 */
+const openForm = (type: string, row: any, newStatus: number, tabType: number) => {
+	formRef.value.open(type, row, newStatus, tabType)
+}
+
+/** 查看商品详情 */
+const openDetail = (type: string, row: any, newStatus: number) => {
+	formRef.value.open(type, row, newStatus)
+	// push({ name: 'ProductSpuDetail', params: { id } })
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+	try {
+		// 导出的二次确认
+		await message.exportConfirm()
+		// 发起导出
+		exportLoading.value = true
+		const data = await ProductSpuApi.exportSpu(queryParams)
+		download.excel(data, '商品列表.xls')
+	} catch {
+	} finally {
+		exportLoading.value = false
 	}
+}
+
+/** 获取分类的节点的完整结构 */
+const categoryList = ref() // 分类树
+const formatCategoryName = (categoryId: number) => {
+	return treeToString(categoryList.value, categoryId)
+}
+
+/** 激活时 */
+onActivated(() => {
+	getList()
+})
+
+/** 初始化 **/
+onMounted(async () => {
+	await getTabsCount()
+	await getList()
+	// 获得分类树
+	const data = await ProductCategoryApi.getCategoryList({})
+	categoryList.value = handleTree(data, 'id', 'parentId')
+})
+</script>
 
-	/** 商品图预览 */
-	const imagePreview = (imgUrl : string) => {
-		createImageViewer({
-			urlList: [imgUrl]
-		})
-	}
+<style lang="scss" scoped>
+.spu-div {
+	position: relative;
+	min-height: 400px;
+	border: none;
+}
 
-	/** 搜索按钮操作 */
-	const handleQuery = () => {
-		getList()
-	}
+::v-deep .el-card__body {
+	padding: 0;
+}
 
-	/** 重置按钮操作 */
-	const resetQuery = () => {
-		queryParams.value.categoryId = undefined
-		queryParams.value.createTime = undefined
-		queryParams.value.name = ""
-		// queryFormRef.value.resetFields()
-		// console.log(queryParams.value)
-		// console.log(queryFormRef.value)
-		handleQuery()
-	}
+::v-deep .parent-tabs .el-tabs__nav-wrap::after {
+	position: static !important;
+}
+::v-deep .el-tabs__header {
+	margin: 0;
+}
 
-	const formRef = ref()
-	/** 新增或修改 */
-	const openForm = (type : string, row : any, newStatus : number, tabType : number) => {
-		formRef.value.open(type, row, newStatus, tabType)
-	}
+::v-deep .parent-tabs .el-tabs__active-bar {
 
-	/** 查看商品详情 */
-	const openDetail = (type : string, row : any, newStatus : number) => {
-		formRef.value.open(type, row, newStatus)
-		// push({ name: 'ProductSpuDetail', params: { id } })
-	}
+	background-color: unset;
+}
 
-	/** 导出按钮操作 */
-	const handleExport = async () => {
-		try {
-			// 导出的二次确认
-			await message.exportConfirm()
-			// 发起导出
-			exportLoading.value = true
-			const data = await ProductSpuApi.exportSpu(queryParams)
-			download.excel(data, '商品列表.xls')
-		} catch {
-		} finally {
-			exportLoading.value = false
-		}
-	}
+.searchMore {
+	text-align: right;
+	background: #f3f5f8;
+	padding: 10px;
+	position: absolute;
+	height: 100px;
+	width: calc(100% - 20px);
+	z-index: 111;
+	box-shadow: 0px 9px 6px rgba(0, 0, 0, 0.2);
 
-	/** 获取分类的节点的完整结构 */
-	const categoryList = ref() // 分类树
-	const formatCategoryName = (categoryId : number) => {
-		return treeToString(categoryList.value, categoryId)
-	}
 
-	/** 激活时 */
-	onActivated(() => {
-		getList()
-	})
+}
 
-	/** 初始化 **/
-	onMounted(async () => {
-		await getTabsCount()
-		await getList()
-		// 获得分类树
-		const data = await ProductCategoryApi.getCategoryList({})
-		categoryList.value = handleTree(data, 'id', 'parentId')
-	})
-</script>
-<style lang="scss" scoped>
-	.spu-div {
-		position: relative;
-		min-height: 400px;
-	}
 
 
-	::v-deep .parent-tabs .el-tabs__nav-wrap::after {
-		position: static !important;
+.product-card {
 
-	}
+	font-size: 14px;
+	margin: 10px;
 
-	::v-deep .parent-tabs .el-tabs__active-bar {
+	.el-card {
+		padding: 15px;
+		cursor: pointer;
+		position: relative;
 
-		background-color: unset;
+		:deep(.el-card__body) {
+			padding: unset;
+		}
 	}
 
-	.searchMore {
-		text-align: right;
-		background: #f3f5f8;
-		padding: 10px;
+	.setting {
+		width: 30px;
+		top: 0px;
+		right: 0px;
 		position: absolute;
-		height: 100px;
-		width: calc(100% - 20px);
-		z-index: 111;
-		box-shadow: 0px 9px 6px rgba(0, 0, 0, 0.2);
-
-
+		height: 30px;
+		line-height: 30px;
+		text-align: center;
+		display: flex;
+		align-items: center;
+		justify-content: center;
 	}
 
-	.el-tabs {
-		position: absolute;
-		z-index: 111;
-		top: 25px;
-		left: 40px;
+	.setting:hover {
+		background: #666
 	}
 
-	.product-card {
-
-		font-size: 14px;
-		margin: 10px;
-
-		.el-card {
-			padding: 15px;
-			cursor: pointer;
-			position: relative;
-
-			:deep(.el-card__body) {
-				padding: unset;
-			}
-		}
-
-		.setting {
-			width: 30px;
-			top: 0px;
-			right: 0px;
-			position: absolute;
-			height: 30px;
-			line-height: 30px;
-			text-align: center;
-			display: flex;
-			align-items: center;
-			justify-content: center;
-		}
-
-		.setting:hover {
-			background: #666
-		}
-
-		p,
-		div {
-			margin: unset;
-			padding: unset;
-		}
+	p,
+	div {
+		margin: unset;
+		padding: unset;
 	}
+}
 
-	.spu-table-expand {
-		padding-left: 42px;
+.spu-table-expand {
+	padding-left: 42px;
 
-		:deep(.el-form-item__label) {
-			width: 82px;
-			font-weight: bold;
-			color: #99a9bf;
-		}
+	:deep(.el-form-item__label) {
+		width: 82px;
+		font-weight: bold;
+		color: #99a9bf;
 	}
+}
 </style>

+ 0 - 2
src/views/mall/trade/order/components/OrderBaseInfo.vue

@@ -204,8 +204,6 @@
   // 暴露给父组件
   defineExpose({ getDetail }) 
 	const message = useMessage() // 消息弹窗
-
-
 	onMounted(async () => {
     getDetail()
 	})

+ 67 - 23
src/views/mall/trade/order/components/OrderIndex.vue

@@ -5,7 +5,6 @@
 			<div class="my-header">
 				<div class="my-header-left">{{dialogTitle}}</div>
 				<div class="my-header-right">
-
 					<span @click="fullScreen">
 						<Icon :icon="isFullScreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'" />
 					</span>
@@ -18,8 +17,9 @@
 			</div>
 		</template>
 		<ContentWrap v-loading="formLoading" style="max-height:600px;overflow-y: auto;">
-			<div class="left">
-				<!-- <SPuUploadImg v-model="" :disabled="isDetail" /> -->
+			<div class="left" style="position: relative;overflow: hidden;">
+				<!-- 默认回显第一个商品的主图 -->
+				<SPuUploadImg v-model="formData.items[0].picUrl" :disabled="true" v-if="activeName == 'info'" />
 				<el-tabs v-model="activeName" tab-position="left" class="child-tabs">
 					<el-tab-pane label="基本信息" name="info" />
 					<el-tab-pane label="商品" name="product" />
@@ -30,7 +30,9 @@
           <el-tab-pane label="支付" name="pay" />
           <el-tab-pane label="日志" name="logs" />
 				</el-tabs>
+
 			</div>
+		
 			<div class="right">
 				<div v-if="activeName == 'info'">
 					<OrderBaseInfo ref="baseInfoRef" :is-detail="false" :id="orderId" />
@@ -107,7 +109,19 @@
   const orderId = ref(0)
 	const formData = ref({})
 	/** 打开弹窗 */
+
+	const isMobile = ref(false);
+
+	function checkDeviceType() {
+		const userAgent = navigator.userAgent;
+		// 简单的移动设备检测逻辑,可以根据需要增加更多检查
+		isMobile.value = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
+	}
+
+	 // 初次检查
 	const open = async (type:string,row:object,no:string) => {
+		checkDeviceType();
+		console.log(isMobile.value)
     orderId.value = row.id
 		formData.value = row
     dialogTitle.value = "查看-"+no
@@ -137,8 +151,8 @@
 	const handleDelivery = (id) =>{
 		deliveryFormRef.value?.open("订单列表",id)
 	}
-	const handleRemark = (id,remark) => {
-		updateRemarkForm.value?.open(id,remark)
+	const handleRemark = (id) => {
+		updateRemarkForm.value?.open(id,"DetailOpen")
 	}
 	const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
 	
@@ -146,6 +160,7 @@
 	const close = () => {
 		dialogVisible.value = false
 	}
+
 </script>
 <style type="text/css">
 	.el-dialog__body {
@@ -173,18 +188,55 @@
 		padding: 0;
 		margin: 0
 	}
+
+	
 </style>
 <style lang="scss" scoped>
+
+	//当屏幕最大宽度为768时,走这套样式
+	@media screen and (max-width: 768px) {
+		::v-deep .el-row{
+			flex-direction: column;
+		}
+		::v-deep .el-row .el-col:last-child{
+			border-top: 1px solid #ebeef5;
+		}
+		::v-deep .el-col-12{
+			max-width: 100%;
+		}
+		::v-deep .el-form-item{
+			flex-direction: column;
+			flex-wrap: wrap;
+			align-items: flex-start;
+		}
+		::v-deep .el-form-item--default .el-form-item__label{
+			border: none;
+			justify-content:flex-start;
+			width: 100% !important;
+			text-indent: 12px;
+			background: aliceblue;
+		}
+		::v-deep .el-form-item__content{
+			overflow: auto;
+			width: 100%;
+			padding-left: 0 !important;
+			text-indent: 12px;
+			border-top: 1px solid #ebeef5;
+		}
+		::v-deep .el-descriptions{
+			overflow-x: auto;
+		}
+		.my-header-right span{
+			width: 6vw !important;
+    	height: 6vh !important;
+			line-height: 6vh !important;
+		}
+	}
+
 	::v-deep .left {
 		width: 106px;
 		float: left;
 
-		img {
-			// width: 98%;
-			// border-bottom: 2px solid #e4e7ee;
-			// border-right: 2px solid #e4e7ee;
-			// margin-bottom: -5px;
-		}
 	}
 
 	.child-tabs {
@@ -192,21 +244,13 @@
 		margin-top: -7px;
 	}
 
-	::v-deep .child-tabs .is-active {
-		// border-left: 2px solid;
-	}
 
-	::v-deep .child-tabs .el-tabs__active-bar {
-		// background-color: #30fdff;
-		// background-color: unset;
-	}
 
 	::v-deep .child-tabs .el-tabs__item {
 		width: 106px;
 		justify-content: center;
 	}
 
-	::v-deep .child-tabs .el-tabs__item {}
 
 	.right {
 		padding: 10px 0 60px;
@@ -227,10 +271,10 @@
 		align-items: center;
 
 		&-left {
-			font-weight: bold;
-			font-size: 18px;
-			padding: 20px;
-			padding-bottom: 10px
+			// font-weight: bold;
+			// font-size: 1rem;
+			padding: 1rem;
+			// padding-bottom: 10px
 		}
 
 		&-right {

+ 2 - 2
src/views/mall/trade/order/components/OrderLogistics.vue

@@ -72,10 +72,10 @@
       display: flex;
       flex-direction: column;
       align-items: flex-start;
-      width: 355px;
+      width: 15rem;
+      padding: 0 1rem;
       border: 1px solid #ebeef5;
       height: 180px;
-      padding: 0 20px;
       border-radius: 10px;
       float: left;
       margin: 10px;

+ 8 - 7
src/views/mall/trade/order/components/OrderProduct.vue

@@ -49,26 +49,26 @@
       </el-col>
     </el-row>
 	</el-form>
-  <el-descriptions>
+  <el-descriptions width="100">
       <el-descriptions-item labelClassName="no-colon">
         <el-row width="100%">
           <el-col :span="24">
-            <el-table :data="formData.items" border width="150" > 
-              <el-table-column label="商品图片">
+            <el-table :data="formData.items" border  > 
+              <el-table-column label="商品图片" width="100">
                 <template #default="{ row }">
                   <!--  -->
-                  <div style="height: 56px;width: 100px;margin: 0 auto;text-align: center;">
+                  <div style="height: 56px;margin: 0 auto;text-align: center;">
                     <img :src="row.picUrl" style="max-width: 100%;max-height: 100%;" />
                   </div>
                   
                 </template>
               </el-table-column>
-              <el-table-column label="商品名称" prop="spuName">
+              <el-table-column label="商品名称" prop="spuName" width="150"  >
                 <template #default="{ row }">
                   {{ row.spuName }}
                 </template>
               </el-table-column>
-              <el-table-column label="商品条码" prop="price" width="150">
+              <el-table-column label="商品条码" prop="price" width="100">
                 <template #default="{ row }">{{ row.spuId }}</template>
               </el-table-column>
               <el-table-column label="销售价" prop="price" width="100">
@@ -81,7 +81,7 @@
               <el-table-column label="小计" prop="payPrice" width="100">
                 <template #default="{ row }">{{ fenToYuan(row.payPrice) }}元</template>
               </el-table-column>
-              <el-table-column label="备注" prop="afterSaleStatus" width="120">
+              <el-table-column label="备注" prop="afterSaleStatus" >
                 <template #default="{ row }">
                   <dict-tag
                     :type="DICT_TYPE.TRADE_ORDER_ITEM_AFTER_SALE_STATUS"
@@ -143,5 +143,6 @@
   }
   .el-descriptions{
     margin-top: 30px;
+    overflow-x: auto;
   }
 </style>

+ 4 - 3
src/views/mall/trade/order/components/OrderService.vue

@@ -55,10 +55,11 @@
       display: flex;
       flex-direction: column;
       align-items: flex-start;
-      width: 355px;
+      
       border: 1px solid #ebeef5;
-      height: 120px;
-      padding: 0 20px;
+      width: 15rem;
+      height: 7.5rem;
+      padding: 0 1rem;
       border-radius: 10px;
       float: left;
       margin: 10px;

+ 19 - 7
src/views/mall/trade/order/form/OrderUpdateRemarkForm.vue

@@ -1,9 +1,10 @@
 <template>
   <Dialog v-model="dialogVisible" title="商家备注" width="70%" >
-    <div style="max-height:800px;overflow-y:auto"> 
+    <div style="max-height:500px;overflow-y:auto" v-if="showDetail"> 
       <OrderBaseInfo ref="infoRef" :is-detail="true" :id="formData.id" style="margin-bottom:30px" />
       <OrderProduct ref="infoRef" :is-detail="isDetail" :id="formData.id" />
-      <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
+    </div>
+    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px" v-else>
         <el-form-item label="备注">
           <el-input
             v-model="formData.remark"
@@ -13,8 +14,17 @@
           />
         </el-form-item>
       </el-form>
-    </div>
     <template #footer>
+      <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px" v-if="showDetail">
+        <el-form-item label="备注">
+          <el-input
+            v-model="formData.remark"
+            :rows="3"
+            placeholder="请输入订单备注"
+            type="textarea"
+          />
+        </el-form-item>
+      </el-form>
       <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
@@ -36,16 +46,18 @@ const formData = ref({
   remark: '' // 订单备注
 })
 const formRef = ref() // 表单 Ref
-
+const showDetail = ref(true) // 是否显示详情
 /** 打开弹窗 */
-const open = async (id,remark) => {
+const open = async (id,openType) => {
   resetForm()
   // 设置数据
   formData.value.id = id
-  formData.value.remark = remark
   getDetail(id)
   dialogVisible.value = true
-  
+  // 如果openType是DetailOpen则是从详情页打开的,不需要显示表单,否则从首页快捷方式打开的需要显示表单
+  if(openType=='DetailOpen'){
+    showDetail.value = false
+  }
 }
 const getDetail = async (id) => {
     if (id) {

+ 362 - 365
src/views/mall/trade/order/index.vue

@@ -2,146 +2,117 @@
 	<ContentWrap class="order-div">
 		<!-- 搜索 -->
 		<div style="position: relative;">
-			<div style="text-align: right;background: #fafbfc;padding: 10px;">
-
-				<el-button :icon="Operation" @click="showSearchMore" />
+			<div style="text-align: right;padding: 10px;">
+				<el-input v-model="queryParams['userNickname']" class="!w-240px" placeholder="搜索客户名称" @keyup.enter="handleQuery">
+					<template #suffix>
+						<Icon class="mr-5px" icon="ep:search" @click="handleQuery" style="cursor: pointer;" />
+					</template>
 
+					<template #append>
+						<el-button :icon="Operation" @click="showSearchMore" />
+					</template>
+				</el-input>
 			</div>
-			<div class="searchMore" v-if="searchMoreShow">
+			<div class="searchMore" v-show="searchMoreShow">
 				<el-form ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px" label-width="68px">
-			<el-form-item label="订单状态" prop="status">
-				<el-select v-model="queryParams.status" class="!w-280px" clearable placeholder="全部">
-					<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_STATUS)" :key="dict.value"
-						:label="dict.label" :value="dict.value" />
-				</el-select>
-			</el-form-item>
-			<el-form-item label="支付方式" prop="payChannelCode">
-				<el-select v-model="queryParams.payChannelCode" class="!w-280px" clearable placeholder="全部">
-					<el-option v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value"
-						:label="dict.label" :value="dict.value" />
-				</el-select>
-			</el-form-item>
-			<el-form-item label="创建时间" prop="createTime">
-				<el-date-picker v-model="queryParams.createTime"
-					:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-280px"
-					end-placeholder="自定义时间" start-placeholder="自定义时间" type="daterange"
-					value-format="YYYY-MM-DD HH:mm:ss" />
-			</el-form-item>
-			<el-form-item label="订单来源" prop="terminal">
-				<el-select v-model="queryParams.terminal" class="!w-280px" clearable placeholder="全部">
-					<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TERMINAL)" :key="dict.value"
-						:label="dict.label" :value="dict.value" />
-				</el-select>
-			</el-form-item>
-			<el-form-item label="订单类型" prop="type">
-				<el-select v-model="queryParams.type" class="!w-280px" clearable placeholder="全部">
-					<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_TYPE)" :key="dict.value"
-						:label="dict.label" :value="dict.value" />
-				</el-select>
-			</el-form-item>
-			<el-form-item label="配送方式" prop="deliveryType">
-				<el-select v-model="queryParams.deliveryType" class="!w-280px" clearable placeholder="全部">
-					<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)" :key="dict.value"
-						:label="dict.label" :value="dict.value" />
-				</el-select>
-			</el-form-item>
-			<el-form-item v-if="queryParams.deliveryType === DeliveryTypeEnum.EXPRESS.type" label="快递公司"
-				prop="logisticsId">
-				<el-select v-model="queryParams.logisticsId" class="!w-280px" clearable placeholder="全部">
-					<el-option v-for="item in deliveryExpressList" :key="item.id" :label="item.name" :value="item.id" />
-				</el-select>
-			</el-form-item>
-			<el-form-item v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" label="自提门店"
-				prop="pickUpStoreId">
-				<el-select v-model="queryParams.pickUpStoreId" class="!w-280px" clearable multiple placeholder="全部">
-					<el-option v-for="item in pickUpStoreList" :key="item.id" :label="item.name" :value="item.id" />
-				</el-select>
-			</el-form-item>
-			<el-form-item v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" label="核销码"
-				prop="pickUpVerifyCode">
-				<el-input v-model="queryParams.pickUpVerifyCode" class="!w-280px" clearable placeholder="请输入自提核销码"
-					@keyup.enter="handleQuery" />
-			</el-form-item>
-			<el-form-item label="聚合搜索">
-				<el-input v-show="true" v-model="queryParams[queryType.queryParam]"
-					:type="queryType.queryParam === 'userId' ? 'number' : 'text'" class="!w-280px" clearable
-					placeholder="请输入">
-					<template #prepend>
-						<el-select v-model="queryType.queryParam" class="!w-110px" clearable placeholder="全部"
-							@change="inputChangeSelect">
-							<el-option v-for="dict in dynamicSearchList" :key="dict.value" :label="dict.label"
+					<el-form-item label="订单状态" prop="status">
+						<el-select v-model="queryParams.status" clearable placeholder="全部">
+							<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_STATUS)" :key="dict.value"
+								:label="dict.label" :value="dict.value" />
+						</el-select>
+					</el-form-item>
+					<el-form-item label="支付方式" prop="payChannelCode">
+						<el-select v-model="queryParams.payChannelCode" clearable placeholder="全部">
+							<el-option v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value"
+								:label="dict.label" :value="dict.value" />
+						</el-select>
+					</el-form-item>
+					<el-form-item label="创建时间" prop="createTime">
+						<el-date-picker v-model="queryParams.createTime"
+							:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" end-placeholder="自定义时间"
+							start-placeholder="自定义时间" type="daterange" value-format="YYYY-MM-DD HH:mm:ss" style="width: auto;" />
+					</el-form-item>
+					<el-form-item label="订单来源" prop="terminal">
+						<el-select v-model="queryParams.terminal" clearable placeholder="全部">
+							<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TERMINAL)" :key="dict.value" :label="dict.label"
 								:value="dict.value" />
 						</el-select>
-					</template>
-				</el-input>
-			</el-form-item>
-			<el-row>
-				<el-col>
-						<el-form-item>
-							<el-button @click="hideSearchMore">
-								收起
-							</el-button>
-							<el-button @click="resetQuery">
-								<!-- <Icon class="mr-5px" icon="ep:refresh" /> -->
-								重置
-							</el-button>
-							<el-button @click="handleQuery"  plain type="primary">
-								<Icon class="mr-5px" icon="ep:search" />
-								搜索
-							</el-button>
-						</el-form-item>
-				</el-col>
-			</el-row>
-			
-		</el-form>
+					</el-form-item>
+					<el-form-item label="订单类型" prop="type">
+						<el-select v-model="queryParams.type" clearable placeholder="全部">
+							<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_TYPE)" :key="dict.value"
+								:label="dict.label" :value="dict.value" />
+						</el-select>
+					</el-form-item>
+					<el-form-item label="配送方式" prop="deliveryType">
+						<el-select v-model="queryParams.deliveryType" clearable placeholder="全部">
+							<el-option v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)" :key="dict.value"
+								:label="dict.label" :value="dict.value" />
+						</el-select>
+					</el-form-item>
+					<el-form-item v-if="queryParams.deliveryType === DeliveryTypeEnum.EXPRESS.type" label="快递公司"
+						prop="logisticsId">
+						<el-select v-model="queryParams.logisticsId" clearable placeholder="全部">
+							<el-option v-for="item in deliveryExpressList" :key="item.id" :label="item.name" :value="item.id" />
+						</el-select>
+					</el-form-item>
+					<el-form-item v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" label="自提门店"
+						prop="pickUpStoreId">
+						<el-select v-model="queryParams.pickUpStoreId" clearable multiple placeholder="全部">
+							<el-option v-for="item in pickUpStoreList" :key="item.id" :label="item.name" :value="item.id" />
+						</el-select>
+					</el-form-item>
+					<!-- <el-form-item v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" label="核销码"
+				prop="pickUpVerifyCode">
+				<el-input v-model="queryParams.pickUpVerifyCode"  clearable placeholder="请输入自提核销码"
+					@keyup.enter="handleQuery" />
+			</el-form-item> -->
+					<el-form-item label="聚合搜索">
+						<el-input v-show="true" v-model="queryParams[queryType.queryParam]"
+							:type="queryType.queryParam === 'userId' ? 'number' : 'text'" clearable placeholder="请输入">
+
+							<template #prepend>
+								<el-select v-model="queryType.queryParam" class="!w-110px" clearable placeholder="全部"
+									@change="inputChangeSelect">
+									<el-option v-for="dict in dynamicSearchList" :key="dict.value" :label="dict.label"
+										:value="dict.value" />
+								</el-select>
+							</template>
+						</el-input>
+					</el-form-item>
+					<el-row>
+						<el-col>
+							<el-form-item>
+								<el-button @click="hideSearchMore">
+									收起
+								</el-button>
+								<el-button @click="resetQuery">
+									<!-- <Icon class="mr-5px" icon="ep:refresh" /> -->
+									重置
+								</el-button>
+								<el-button @click="handleQuery" plain type="primary">
+									<Icon class="mr-5px" icon="ep:search" />
+									搜索
+								</el-button>
+							</el-form-item>
+						</el-col>
+					</el-row>
+
+				</el-form>
 			</div>
 		</div>
-		<!-- 列表 -->
-		<!-- <el-table v-loading="loading" :data="list" row-key="id">
-			<OrderTableColumn :list="list" :pick-up-store-list="pickUpStoreList">
-				<template #default="{ row }">
-					<div class="flex items-center justify-center">
-						<el-button v-hasPermi="['trade:order:query']" link type="primary" >
-							<Icon icon="ep:notification" />
-							详情
-						</el-button>
-						<el-dropdown v-hasPermi="['trade:order:update']"
-							@command="(command) => handleCommand(command, row)">
-							<el-button link type="primary">
-								<Icon icon="ep:d-arrow-right" />
-								更多
-							</el-button>
-							<template #dropdown>
-								<el-dropdown-menu>
-									如果是【快递】,并且【未发货】,则展示【发货】按钮
-									<el-dropdown-item v-if="
-                      row.deliveryType === DeliveryTypeEnum.EXPRESS.type &&
-                      row.status === TradeOrderStatusEnum.UNDELIVERED.status
-                    "command="delivery">
-										<Icon icon="ep:takeaway-box" />
-										发货
-									</el-dropdown-item>
-									<el-dropdown-item command="remark">
-										<Icon icon="ep:chat-line-square" />
-										备注
-									</el-dropdown-item>
-								</el-dropdown-menu>
-							</template>
-						</el-dropdown>
-					</div>
-				</template>
-			</OrderTableColumn>
-		</el-table> -->
+
 		<el-row>
-		
-			<el-col  v-for="(o, index) in list" class="product-card" :key="index" :span="7" :xl="7" :lg="7" :md="24" :sm="24" :xs="24" @mouseover="handleMouseOver(index)" @mouseout="handleMouseOut(index)">
-				<el-card @click="openDetail('view',o,o.no)">
+
+			<el-col v-for="(o, index) in list" class="product-card" :key="index" :span="7" :xl="7" :lg="7" :md="24" :sm="24"
+				:xs="24" @mouseover="handleMouseOver(index)" @mouseout="handleMouseOut(index)">
+				<el-card @click="openDetail('view', o, o.no)">
 					<div style="display: flex;justify-content: space-between;align-items: center;margin-bottom: 5px;">
 						<p style="width: 95%;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;font-size: 16px;color:#000"
-							title=""><span v-for="item in o.items" :key="item.id">{{item.spuName}}</span>
+							title=""><span v-for="item in o.items" :key="item.id">{{ item.spuName }}</span>
 						</p>
-						<div class="setting" @click.stop="" >
-								<el-dropdown v-hasPermi="['trade:order:update']" @command="(command) => handleCommand(command, row)">
+						<div class="setting" @click.stop="">
+							<el-dropdown v-hasPermi="['trade:order:update']" @command="(command) => handleCommand(command, row)">
 								<span>
 									<el-icon size="20" color="rgb(220 223 231)" v-show="o.showSetting">
 										<Operation />
@@ -150,20 +121,25 @@
 										<arrow-down />
 									</el-icon> -->
 								</span>
-								<template #dropdown >
+
+								<template #dropdown>
 									<el-dropdown-menu @mouseover="handleMouseOver(index)" @mouseout="handleMouseOut(index)">
-										<el-dropdown-item @click="handleDelivery(o.id)" v-if="o.deliveryType === DeliveryTypeEnum.EXPRESS.type && o.status === TradeOrderStatusEnum.UNDELIVERED.status">发货</el-dropdown-item>
-										<el-dropdown-item @click="handleRemark(o.id,o.remark)">备注</el-dropdown-item>
-										<el-dropdown-item @click="handleInvoice" v-if="o.status === TradeOrderStatusEnum.COMPLETED.status">开发票</el-dropdown-item>
-										<el-dropdown-item v-if="o.deliveryType === DeliveryTypeEnum.EXPRESS.type && o.status === TradeOrderStatusEnum.UNDELIVERED.status" @click="updateAddress(o.id,o.receiverAreaName,o.receiverMobile,o.receiverAreaId,o.receiverDetailAddress)">修改地址</el-dropdown-item>
+										<el-dropdown-item @click="handleDelivery(o.id)"
+											v-if="o.deliveryType === DeliveryTypeEnum.EXPRESS.type && o.status === TradeOrderStatusEnum.UNDELIVERED.status">发货</el-dropdown-item>
+										<el-dropdown-item @click="handleRemark(o.id, o.remark)">备注</el-dropdown-item>
+										<el-dropdown-item @click="handleInvoice"
+											v-if="o.status === TradeOrderStatusEnum.COMPLETED.status">开发票</el-dropdown-item>
+										<el-dropdown-item
+											v-if="o.deliveryType === DeliveryTypeEnum.EXPRESS.type && o.status === TradeOrderStatusEnum.UNDELIVERED.status"
+											@click="updateAddress(o.id, o.receiverAreaName, o.receiverMobile, o.receiverAreaId, o.receiverDetailAddress)">修改地址</el-dropdown-item>
 									</el-dropdown-menu>
 								</template>
 							</el-dropdown>
 						</div>
 					</div>
 					<div style="display:flex;align-items: center;">
-						<div style="width: 206px;height: 116px;margin-right:10px;border:1px solid rgb(220 223 231);border-radius: 5px;display: flex;align-items: center;justify-content: center;"
-							>
+						<div
+							style="width: 206px;height: 116px;margin-right:10px;border:1px solid rgb(220 223 231);border-radius: 5px;display: flex;align-items: center;justify-content: center;">
 							<img :src="o.items[0].picUrl" style="width: auto;height: auto;max-width: 100%;max-height: 100%;" />
 						</div>
 
@@ -171,9 +147,9 @@
 							<p>¥{{ o.payPrice }}</p>
 							<p>{{ o.no }}</p>
 							<p>{{ getDictObj(DICT_TYPE.TRADE_ORDER_STATUS, o.status)?.label }}</p>
-							<p>{{o.user.nickname}}</p>
-							<p><span class="year">{{timestampToY(o.createTime)}}</span>{{ timestampToMD(o.createTime) }}</p>
-							
+							<p>{{ o.user.nickname }}</p>
+							<p><span class="year">{{ timestampToY(o.createTime) }}</span>{{ timestampToMD(o.createTime) }}</p>
+
 						</div>
 					</div>
 				</el-card>
@@ -196,64 +172,128 @@
 </template>
 
 <script lang="ts" setup>
-	import type { FormInstance } from 'element-plus'
-	import OrderDeliveryForm from '@/views/mall/trade/order/form/OrderDeliveryForm.vue'
-	import OrderUpdateRemarkForm from '@/views/mall/trade/order/form/OrderUpdateRemarkForm.vue'
-	import * as TradeOrderApi from '@/api/mall/trade/order'
-	import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore'
-	import { DICT_TYPE, getIntDictOptions, getStrDictOptions,getDictObj } from '@/utils/dict'
-	import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express'
-	import { DeliveryTypeEnum, TradeOrderStatusEnum } from '@/utils/constants'
-	import { Setting, Search, Operation } from '@element-plus/icons-vue'
-	import { OrderTableColumn } from './components'
-	import { formatDate } from '@/utils/formatTime'
-	import OrderIndex from "./components/OrderIndex.vue"
-	import OrderUpdateAddressForm from '@/views/mall/trade/order/form/OrderUpdateAddressForm.vue'
-
-	//时间戳转换为yyyy/mm/dd
-	function timestampToMD(timestamp) {
-    var date = new Date(timestamp);
-    var year = date.getFullYear();
-    var month = ("0" + (date.getMonth() + 1)).slice(-2); // 补零操作
-    var day = ("0" + date.getDate()).slice(-2);
-    return month + "/" + day;
-	}
-	function timestampToY(timestamp) {
-    var date = new Date(timestamp);
-    var year = date.getFullYear();
-    var month = ("0" + (date.getMonth() + 1)).slice(-2); // 补零操作
-    var day = ("0" + date.getDate()).slice(-2);
-    return year + "/" ;
-	}
-	const searchMoreShow = ref(false)
-	// 鼠标移入显示变动图标
-	function handleMouseOver(index) {
-		list.value[index].showSetting = true;
-	}
-	// 鼠标移出不显示图标
-	function handleMouseOut(index) {
-		list.value[index].showSetting = false;
-	}
-	// 打开更多搜索条件
-	const showSearchMore = () => {
-		searchMoreShow.value = !searchMoreShow.value
-	}
-	const hideSearchMore = () => {
+import type { FormInstance } from 'element-plus'
+import OrderDeliveryForm from '@/views/mall/trade/order/form/OrderDeliveryForm.vue'
+import OrderUpdateRemarkForm from '@/views/mall/trade/order/form/OrderUpdateRemarkForm.vue'
+import * as TradeOrderApi from '@/api/mall/trade/order'
+import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore'
+import { DICT_TYPE, getIntDictOptions, getStrDictOptions, getDictObj } from '@/utils/dict'
+import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express'
+import { DeliveryTypeEnum, TradeOrderStatusEnum } from '@/utils/constants'
+import { Setting, Search, Operation } from '@element-plus/icons-vue'
+import { OrderTableColumn } from './components'
+import { formatDate } from '@/utils/formatTime'
+import OrderIndex from "./components/OrderIndex.vue"
+import OrderUpdateAddressForm from '@/views/mall/trade/order/form/OrderUpdateAddressForm.vue'
+
+//时间戳转换为yyyy/mm/dd
+function timestampToMD(timestamp) {
+	var date = new Date(timestamp);
+	var year = date.getFullYear();
+	var month = ("0" + (date.getMonth() + 1)).slice(-2); // 补零操作
+	var day = ("0" + date.getDate()).slice(-2);
+	return month + "/" + day;
+}
+function timestampToY(timestamp) {
+	var date = new Date(timestamp);
+	var year = date.getFullYear();
+	var month = ("0" + (date.getMonth() + 1)).slice(-2); // 补零操作
+	var day = ("0" + date.getDate()).slice(-2);
+	return year + "/";
+}
+const searchMoreShow = ref(false)
+// 鼠标移入显示变动图标
+function handleMouseOver(index) {
+	list.value[index].showSetting = true;
+}
+// 鼠标移出不显示图标
+function handleMouseOut(index) {
+	list.value[index].showSetting = false;
+}
+// 打开更多搜索条件
+const showSearchMore = () => {
+	searchMoreShow.value = !searchMoreShow.value
+}
+const hideSearchMore = () => {
+	searchMoreShow.value = false
+}
+const formRef = ref()
+const openDetail = (type: string, row: {}, no: string) => {
+	formRef.value.open(type, row, no)
+}
+
+defineOptions({ name: 'TradeOrder' })
+const { currentRoute, push } = useRouter() // 路由跳转
+const loading = ref(true) // 列表的加载中
+const total = ref(2) // 列表的总页数
+const list = ref<TradeOrderApi.OrderVO[]>([]) // 列表的数据
+const queryFormRef = ref<FormInstance>() // 搜索的表单
+// 表单搜索
+const queryParams = ref({
+	pageNo: 1, // 页数
+	pageSize: 10, // 每页显示数量
+	status: undefined, // 订单状态
+	payChannelCode: undefined, // 支付方式
+	createTime: undefined, // 创建时间
+	terminal: undefined, // 订单来源
+	type: undefined, // 订单类型
+	deliveryType: undefined, // 配送方式
+	logisticsId: undefined, // 快递公司
+	pickUpStoreId: undefined, // 自提门店
+	pickUpVerifyCode: undefined // 自提核销码
+})
+const queryType = reactive({ queryParam: '' }) // 订单搜索类型 queryParam
+
+// 订单聚合搜索 select 类型配置(动态搜索)
+const dynamicSearchList = ref([
+	{ value: 'no', label: '订单号' },
+	{ value: 'userId', label: '用户UID' },
+	{ value: 'userNickname', label: '用户昵称' },
+	{ value: 'userMobile', label: '用户电话' }
+])
+/**
+ * 聚合搜索切换查询对象时触发
+ * @param val
+ */
+const inputChangeSelect = (val: string) => {
+	dynamicSearchList.value
+		.filter((item) => item.value !== val)
+		?.forEach((item1) => {
+			// 清除集合搜索无用属性
+			if (queryParams.value.hasOwnProperty(item1.value)) {
+				
+				delete queryParams.value[item1.value]
+			}
+		})
+}
+
+/** 查询列表 */
+const getList = async () => {
+	loading.value = true
+	try {
+		const data = await TradeOrderApi.getOrderPage(unref(queryParams))
+		data.list.forEach(obj => {
+			obj.showSetting = false;
+		});
+		list.value = data.list
+		total.value = data.total
+	} finally {
+		loading.value = false
 		searchMoreShow.value = false
+
 	}
-	const formRef = ref()
-	const openDetail = (type:string,row : {},no:string) => {
-		formRef.value.open(type,row,no)
-	}
-	
-	defineOptions({ name: 'TradeOrder' })
-	const { currentRoute, push } = useRouter() // 路由跳转
-	const loading = ref(true) // 列表的加载中
-	const total = ref(2) // 列表的总页数
-	const list = ref<TradeOrderApi.OrderVO[]>([]) // 列表的数据
-	const queryFormRef = ref<FormInstance>() // 搜索的表单
-	// 表单搜索
-	const queryParams = ref({
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+	queryParams.value.pageNo = 1
+	await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+	queryFormRef.value?.resetFields()
+	queryParams.value = {
 		pageNo: 1, // 页数
 		pageSize: 10, // 每页显示数量
 		status: undefined, // 订单状态
@@ -265,205 +305,162 @@
 		logisticsId: undefined, // 快递公司
 		pickUpStoreId: undefined, // 自提门店
 		pickUpVerifyCode: undefined // 自提核销码
-	})
-	const queryType = reactive({ queryParam: '' }) // 订单搜索类型 queryParam
-
-	// 订单聚合搜索 select 类型配置(动态搜索)
-	const dynamicSearchList = ref([
-		{ value: 'no', label: '订单号' },
-		{ value: 'userId', label: '用户UID' },
-		{ value: 'userNickname', label: '用户昵称' },
-		{ value: 'userMobile', label: '用户电话' }
-	])
-	/**
-	 * 聚合搜索切换查询对象时触发
-	 * @param val
-	 */
-	const inputChangeSelect = (val : string) => {
-		dynamicSearchList.value
-			.filter((item) => item.value !== val)
-			?.forEach((item1) => {
-				// 清除集合搜索无用属性
-				if (queryParams.value.hasOwnProperty(item1.value)) {
-					delete queryParams.value[item1.value]
-				}
-			})
 	}
+	handleQuery()
+}
+
+// /** 查看订单详情 */
+// const openDetail = (id : number) => {
+// 	push({ name: 'TradeOrderDetail', params: { id } })
+// }
+
+/** 操作分发 */
+const deliveryFormRef = ref()
+const updateRemarkForm = ref()
+const updateAddressFormRef = ref() // 收货地址表单 Ref
+const updateAddress = (id, receiverName, receiverMobile, receiverAreaId, receiverDetailAddress) => {
+	updateAddressFormRef.value.open(id, receiverName, receiverMobile, receiverAreaId, receiverDetailAddress)
+}
+const handleDelivery = (id) => {
+	deliveryFormRef.value?.open("订单列表", id)
+}
+const handleRemark = (id) => {
+	updateRemarkForm.value?.open(id)
+}
+
+
+// 监听路由变化更新列表,解决订单保存/更新后,列表不刷新的问题。
+watch(
+	() => currentRoute.value,
+	() => {
+		getList()
+	}
+)
 
-	/** 查询列表 */
-	const getList = async () => {
-		loading.value = true
-		try {
-			const data = await TradeOrderApi.getOrderPage(unref(queryParams))
-			data.list.forEach(obj => {
-				obj.showSetting = false;
-			});
-			list.value = data.list
-			total.value = data.total
-		} finally {
-			loading.value = false
-			searchMoreShow.value = false
+const pickUpStoreList = ref<PickUpStoreApi.DeliveryPickUpStoreVO[]>([]) // 自提门店精简列表
+const deliveryExpressList = ref<DeliveryExpressApi.DeliveryExpressVO[]>([]) // 物流公司
+/** 初始化 **/
+onMounted(async () => {
+	await getList()
+	pickUpStoreList.value = await PickUpStoreApi.getListAllSimple()
+	deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList()
 
-		}
-	}
+})
 
-	/** 搜索按钮操作 */
-	const handleQuery = async () => {
-		queryParams.value.pageNo = 1
-		await getList()
-	}
+</script>
 
-	/** 重置按钮操作 */
-	const resetQuery = () => {
-		queryFormRef.value?.resetFields()
-		queryParams.value = {
-			pageNo: 1, // 页数
-			pageSize: 10, // 每页显示数量
-			status: undefined, // 订单状态
-			payChannelCode: undefined, // 支付方式
-			createTime: undefined, // 创建时间
-			terminal: undefined, // 订单来源
-			type: undefined, // 订单类型
-			deliveryType: undefined, // 配送方式
-			logisticsId: undefined, // 快递公司
-			pickUpStoreId: undefined, // 自提门店
-			pickUpVerifyCode: undefined // 自提核销码
-		}
-		handleQuery()
+<style lang="scss" scoped>
+//当屏幕最大宽度为768时,走这套样式
+@media screen and (max-width: 768px) {
+	.year {
+		display: none
 	}
 
-	// /** 查看订单详情 */
-	// const openDetail = (id : number) => {
-	// 	push({ name: 'TradeOrderDetail', params: { id } })
-	// }
-
-	/** 操作分发 */
-	const deliveryFormRef = ref()
-	const updateRemarkForm = ref()
-	const updateAddressFormRef = ref() // 收货地址表单 Ref
-	const updateAddress = (id,receiverName,receiverMobile,receiverAreaId,receiverDetailAddress) => {
-		updateAddressFormRef.value.open(id,receiverName,receiverMobile,receiverAreaId,receiverDetailAddress)
-	}
-	const handleDelivery = (id) =>{
-		deliveryFormRef.value?.open("订单列表",id)
+	.product-card {
+		margin: 10px 0 !important;
+		;
 	}
-	const handleRemark = (id,remark) => {
-		updateRemarkForm.value?.open(id,remark)
+
+	::v-deep(.el-pagination__sizes),
+	::v-deep(.el-pagination__jump) {
+		display: none;
 	}
+}
 
 
-	// 监听路由变化更新列表,解决订单保存/更新后,列表不刷新的问题。
-	watch(
-		() => currentRoute.value,
-		() => {
-			getList()
-		}
-	)
-
-	const pickUpStoreList = ref<PickUpStoreApi.DeliveryPickUpStoreVO[]>([]) // 自提门店精简列表
-	const deliveryExpressList = ref<DeliveryExpressApi.DeliveryExpressVO[]>([]) // 物流公司
-	/** 初始化 **/
-	onMounted(async () => {
-		await getList()
-		pickUpStoreList.value = await PickUpStoreApi.getListAllSimple()
-		deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList()
-		
-	})
-	
-</script>
-<style lang="scss" scoped>
-	@media screen and (max-width: 768px) {
-		.year{
-			display:none
-		}
-	}
-	.order-div {
-		position: relative;
-		min-height: 400px;
-	}
+.order-div {
+	position: relative;
+	min-height: 400px;
+	border: none;
+}
 
 
-	::v-deep .parent-tabs .el-tabs__nav-wrap::after {
-		position: static !important;
+::v-deep .parent-tabs .el-tabs__nav-wrap::after {
+	position: static !important;
 
-	}
+}
+::v-deep .el-card__body{
+	padding: 0;
+}
+::v-deep .parent-tabs .el-tabs__active-bar {
 
-	::v-deep .parent-tabs .el-tabs__active-bar {
+	background-color: unset;
+}
 
-		background-color: unset;
-	}
+.searchMore {
+	text-align: right;
+	background: #f3f5f8;
+	padding: 10px;
+	position: absolute;
+	// height: 100px;
+	width: calc(100% - 20px);
+	z-index: 111;
+	box-shadow: 0px 9px 6px rgba(0, 0, 0, 0.2);
 
-	.searchMore {
-		text-align: right;
-		background: #f3f5f8;
-		padding: 10px;
-		position: absolute;
-		// height: 100px;
-		width: calc(100% - 20px);
-		z-index: 111;
-		box-shadow: 0px 9px 6px rgba(0, 0, 0, 0.2);
 
+}
+
+.el-tabs {
+	position: absolute;
+	z-index: 111;
+	top: 25px;
+	left: 40px;
+}
+
+.product-card {
+
+	font-size: 14px;
+	margin: 10px;
+
+	.el-card {
+		padding: 15px;
+		cursor: pointer;
+		position: relative;
 
+		:deep(.el-card__body) {
+			padding: unset;
+		}
 	}
 
-	.el-tabs {
+	.setting {
+		width: 30px;
+		top: 0px;
+		right: 0px;
 		position: absolute;
-		z-index: 111;
-		top: 25px;
-		left: 40px;
+		height: 30px;
+		line-height: 30px;
+		text-align: center;
+		display: flex;
+		align-items: center;
+		justify-content: center;
 	}
 
-	.product-card {
-
-		font-size: 14px;
-		margin: 10px;
-
-		.el-card {
-			padding: 15px;
-			cursor: pointer;
-			position: relative;
+	.setting :focus-visible {
+		outline: 0;
+	}
 
-			:deep(.el-card__body) {
-				padding: unset;
-			}
-		}
+	.setting:focus-visible {
+		font-size: 20px;
+	}
 
-		.setting {
-			width: 30px;
-			top: 0px;
-			right: 0px;
-			position: absolute;
-			height: 30px;
-			line-height: 30px;
-			text-align: center;
-			display: flex;
-			align-items: center;
-			justify-content: center;
-		}
-		.setting :focus-visible {
-			outline: 0;
-		}
-		.setting:focus-visible {
-			font-size: 20px;
-		}
-		.setting:hover {
-			background: #666
-		}
+	.setting:hover {
+		background: #666
+	}
 
-		p,
-		div {
-			margin: unset;
-			padding: unset;
-		}
+	p,
+	div {
+		margin: unset;
+		padding: unset;
 	}
+}
 
-	.spu-table-expand {
-		padding-left: 42px;
+.spu-table-expand {
+	padding-left: 42px;
 
-		:deep(.el-form-item__label) {
-			width: 82px;
-			font-weight: bold;
-			color: #99a9bf;
-		}
+	:deep(.el-form-item__label) {
+		width: 82px;
+		font-weight: bold;
+		color: #99a9bf;
 	}
+}
 </style>

+ 147 - 0
src/views/system/sale/merchant/components/MerchantForm.vue

@@ -0,0 +1,147 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
+      <el-form-item label="商户名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入商户名称" />
+      </el-form-item>
+      <el-form-item label="商户状态" prop="status">
+        <el-radio-group v-model="formData.status">
+          <el-radio label="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      
+      <el-form-item label="负责人" prop="contact">
+        <el-input v-model="formData.contact" placeholder="请输入负责人" />
+      </el-form-item>
+      <el-form-item label="所在地" prop="address">
+        <el-input v-model="formData.address" placeholder="请输入所在地" />
+      </el-form-item>
+      <el-form-item label="负责人电话" prop="contactNumber">
+        <el-input v-model="formData.contactNumber" placeholder="请输入负责人电话" />
+      </el-form-item>
+      <el-form-item label="官网" prop="website">
+        <el-input v-model="formData.website" placeholder="请输入官网" />
+      </el-form-item>
+      <el-form-item label="维权电话" prop="complaintsHotline">
+        <el-input v-model="formData.complaintsHotline" placeholder="请输入维权电话" />
+      </el-form-item>
+      <el-form-item label="客服电话" prop="customerServiceHotline">
+        <el-input v-model="formData.customerServiceHotline" placeholder="请输入客服电话" />
+      </el-form-item>
+      <el-form-item label="邮箱" prop="email">
+        <el-input v-model="formData.email" placeholder="请输入邮箱" />
+      </el-form-item>
+      
+      <el-form-item label="服务到期时间" prop="expireTime">
+        <el-date-picker v-model="formData.expireTime" type="date" value-format="x" placeholder="选择服务到期时间" />
+      </el-form-item>
+      <el-form-item label="营业执照" prop="businessLicensePicture">
+        <UploadImg v-model="formData.businessLicensePicture" :limit="1" />
+      </el-form-item>
+      <el-form-item label="简介" prop="description">
+        <Editor v-model="formData.description" height="150px" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+
+<script setup lang="ts">
+import { MerchantApi, MerchantVO } from '@/api/system/sale/merchant'
+
+/** 商户 表单 */
+defineOptions({ name: 'MerchantForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  name: undefined,
+  status: undefined,
+  description: undefined,
+  contact: undefined,
+  address: undefined,
+  contactNumber: undefined,
+  website: undefined,
+  complaintsHotline: undefined,
+  customerServiceHotline: undefined,
+  email: undefined,
+  businessLicensePicture: undefined,
+  expireTime: undefined
+})
+const formRules = reactive({
+  name: [{ required: true, message: '商户名称不能为空', trigger: 'blur' }],
+  status: [{ required: true, message: '商户状态', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await MerchantApi.getMerchant(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as MerchantApi.MerchantVO
+    if (formType.value === 'create') {
+      await MerchantApi.createMerchant(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await MerchantApi.updateMerchant(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    name: undefined,
+    status: undefined,
+    description: undefined,
+    contact: undefined,
+    address: undefined,
+    contactNumber: undefined,
+    website: undefined,
+    complaintsHotline: undefined,
+    customerServiceHotline: undefined,
+    email: undefined,
+    businessLicensePicture: undefined,
+    expireTime: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 57 - 0
src/views/system/sale/merchant/components/MerchantIndex.vue

@@ -0,0 +1,57 @@
+<template>
+  <el-dialog :model-value="dialogVisible" @update:model-value="updateDialogVisible" class="custom-dialog">
+    <div class="dialog-content">
+      <div class="tabs-section">
+        <el-tabs v-model="activeTab" tab-position="left">
+          <el-tab-pane v-for="tab in tabs" :key="tab.name" :label="tab.title" :name="tab.name" />
+        </el-tabs>
+      </div>
+      <div class="component-section">
+        <component :is="currentComponent" />
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, watch, defineAsyncComponent } from 'vue';
+
+const props = defineProps({
+  dialogVisible: Boolean,
+  tabs: Array, // 父组件传来的tabs数组,每个tab对象包含title和name属性
+  components: Object // 父组件传来的组件地址映射,键为tab.name,值为组件路径字符串
+});
+
+const emit = defineEmits(['update:dialogVisible']);
+const componentMap = props.components;
+
+const activeTab = ref(props.tabs[0]?.name || '');
+const currentComponent = ref(null);
+
+watch(activeTab, (newTab) => {
+  if (componentMap[newTab]) {
+    const componentPath = componentMap[newTab];
+    currentComponent.value = defineAsyncComponent(() =>
+      import(/* webpackChunkName: "[request]" */ componentPath)
+    );
+  }
+}, { immediate: true });
+
+function updateDialogVisible(value) {
+  emit('update:dialogVisible', value);
+}
+</script>
+
+<style scoped>
+.custom-dialog .dialog-content {
+  display: flex;
+}
+
+.tabs-section {
+  flex: 1;
+}
+
+.component-section {
+  flex: 3;
+}
+</style>

+ 339 - 0
src/views/system/sale/merchant/index.vue

@@ -0,0 +1,339 @@
+<template>
+  <!-- 列表 -->
+  <ContentWrap style="min-height: 400px;">
+    <div style="position: relative;">
+      <div style="text-align: right;padding: 10px;">
+        <el-button :icon="Operation" @click="showSearchMore" />
+				<el-button v-hasPermi="['sale:merchant:create']" @click="openForm('create', '', 0)">
+					<Icon class="mr-5px" icon="ep:plus" />
+					新增
+				</el-button>
+      </div>
+      <div class="searchMore" v-show="searchMoreShow">
+        <el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form-item label="商户名称" prop="name">
+            <el-input v-model="queryParams.name" placeholder="请输入商户名称" clearable @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="商户状态" prop="status">
+            <el-select v-model="queryParams.status" placeholder="请选择商户状态" clearable>
+              <el-option label="请选择字典生成" value="" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="负责人" prop="contact">
+            <el-input v-model="queryParams.contact" placeholder="请输入负责人" clearable @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="所在地" prop="address">
+            <el-input v-model="queryParams.address" placeholder="请输入所在地" clearable @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="负责人电话" prop="contactNumber">
+            <el-input v-model="queryParams.contactNumber" placeholder="请输入负责人电话" clearable @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="官网" prop="website">
+            <el-input v-model="queryParams.website" placeholder="请输入官网" clearable @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="维权电话" prop="complaintsHotline">
+            <el-input v-model="queryParams.complaintsHotline" placeholder="请输入维权电话" clearable
+              @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="客服电话" prop="customerServiceHotline">
+            <el-input v-model="queryParams.customerServiceHotline" placeholder="请输入客服电话" clearable
+              @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="邮箱" prop="email">
+            <el-input v-model="queryParams.email" placeholder="请输入邮箱" clearable @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="服务到期时间" prop="expireTime">
+            <el-date-picker v-model="queryParams.expireTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
+              start-placeholder="开始日期" end-placeholder="结束日期"
+              :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" />
+          </el-form-item>
+          <el-form-item label="创建时间" prop="createTime">
+            <el-date-picker v-model="queryParams.createTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
+              start-placeholder="开始日期" end-placeholder="结束日期"
+              :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" />
+          </el-form-item>
+          <el-form-item>
+            <el-button @click="hideSearchMore">
+							收起
+						</el-button>
+            <el-button @click="resetQuery">
+                重置
+            </el-button>
+            <el-button @click="handleQuery">
+              <Icon icon="ep:search" class="mr-5px" /> 搜索
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+    <el-row>
+      <el-col v-for="(o, index) in list" class="product-card" :key="index" :span="7" @mouseover="handleMouseOver(index)"
+        @mouseout="handleMouseOut(index)">
+        <el-card @click="openDetail('view')">
+          <div style="display: flex;justify-content: space-between;align-items: center;margin-bottom: 5px;">
+            <p style="width: 100%;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;font-size: 16px;color:#000"
+              :title="o.name">{{ o.name }}
+            </p>
+            <div @click.stop="openForm('update')" v-show="o.showSetting" class="setting"
+              v-hasPermi="['sale:merchant:update']">
+              <el-icon size="20" color="rgb(220 223 231)">
+                <Setting />
+              </el-icon>
+            </div>
+          </div>
+          <div style="display:flex;align-items: center;">
+            <div
+              style="width: 151px;height: 85px;margin-right:10px;border:1px solid rgb(220 223 231);border-radius: 5px;display: flex;align-items: center;justify-content: center;">
+              <img :src="o.picUrl" style="width: auto;height: auto;max-width: 100%;max-height: 100%;" />
+            </div>
+            <div style='line-height: 30px;'>
+              <p>销量:1444</p>
+              <p>商品数量:34</p>
+              <p>所在地:{{ o.address }}</p>
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+    <div v-if="list.length == 0">
+      <p style="text-align: center;margin-top: 100px;">暂无商户</p>
+    </div>
+    <!-- 分页 -->
+    <Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
+      @pagination="getList" />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <MerchantForm ref="formRef" @success="getList" />
+
+  <!-- <MerchantIndex :dialogVisible="isDialogVisible" :tabs="tabs" :components="componentMap" /> -->
+  <MerchantIndex :dialogVisible="isDialogVisible" @update:dialogVisible="updateDialogVisible" :tabs="tabs" :components="componentMap" />
+
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { MerchantApi, MerchantVO } from '@/api/system/sale/merchant'
+import { Setting,Operation } from '@element-plus/icons-vue'
+import MerchantForm from './components/MerchantForm.vue'
+import MerchantIndex from './components/MerchantIndex.vue'
+const isDialogVisible = ref(true);
+const tabs = [
+  { title: '基本信息', name: 'baseInfo' },
+  // 更多tabs...
+];
+const componentMap = {
+  baseInfo: './components/MerchantForm.vue',
+  // 更多组件路径...
+};
+function updateDialogVisible(value) {
+  isDialogVisible.value = value;
+}
+
+
+/** 商户列表 */
+defineOptions({ name: 'Merchant' })
+const searchMoreShow = ref(false)
+// 鼠标移入显示变动图标
+function handleMouseOver(index) {
+  list.value[index].showSetting = true;
+}
+// 鼠标移出不显示图标
+function handleMouseOut(index) {
+  list.value[index].showSetting = false;
+}
+// 打开更多搜索条件
+const showSearchMore = () => {
+  searchMoreShow.value = !searchMoreShow.value
+}
+const hideSearchMore = () => {
+  searchMoreShow.value = false
+}
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<MerchantVO[]>([]) // 列表的数据
+// 列表的总页数
+const total = ref(0)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  name: undefined,
+  status: undefined,
+  description: undefined,
+  contact: undefined,
+  address: undefined,
+  contactNumber: undefined,
+  website: undefined,
+  complaintsHotline: undefined,
+  customerServiceHotline: undefined,
+  email: undefined,
+  expireTime: [],
+  createTime: []
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await MerchantApi.getMerchantPage(queryParams)
+    data.list.forEach(obj => {
+      obj.showSetting = false;
+    });
+
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+  hideSearchMore()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await MerchantApi.deleteMerchant(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch { }
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await MerchantApi.exportMerchant(queryParams)
+    download.excel(data, '商户.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>
+
+<style lang="scss" scoped>
+::v-deep .el-form-item__label {
+  width: auto !important;
+}
+</style>
+
+<style lang="scss" scoped>
+.spu-div {
+  position: relative;
+  min-height: 400px;
+}
+
+
+::v-deep .parent-tabs .el-tabs__nav-wrap::after {
+  position: static !important;
+
+}
+
+::v-deep .parent-tabs .el-tabs__active-bar {
+
+  background-color: unset;
+}
+
+.searchMore {
+  text-align: right;
+  background: #f3f5f8;
+  padding: 10px;
+  position: absolute;
+  width: calc(100% - 20px);
+  z-index: 111;
+  box-shadow: 0px 9px 6px rgba(0, 0, 0, 0.2);
+
+
+}
+
+.el-tabs {
+  position: absolute;
+  z-index: 111;
+  top: 25px;
+  left: 40px;
+}
+
+.product-card {
+
+  font-size: 14px;
+  margin: 10px;
+
+  .el-card {
+    padding: 15px;
+    cursor: pointer;
+    position: relative;
+
+    :deep(.el-card__body) {
+      padding: unset;
+    }
+  }
+
+  .setting {
+    width: 30px;
+    top: 0px;
+    right: 0px;
+    position: absolute;
+    height: 30px;
+    line-height: 30px;
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .setting:hover {
+    background: #666
+  }
+
+  p,
+  div {
+    margin: unset;
+    padding: unset;
+  }
+}
+
+.spu-table-expand {
+  padding-left: 42px;
+
+  :deep(.el-form-item__label) {
+    width: 82px;
+    font-weight: bold;
+    color: #99a9bf;
+  }
+}
+</style>

+ 106 - 0
src/views/system/sale/shop/ShopForm.vue

@@ -0,0 +1,106 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="店铺名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入店铺名称" />
+      </el-form-item>
+      <el-form-item label="店铺状态" prop="status">
+        <el-radio-group v-model="formData.status">
+          <el-radio label="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="商户id" prop="merchantId">
+        <el-input v-model="formData.merchantId" placeholder="请输入商户id" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { ShopApi, ShopVO } from '@/api/system/sale/shop'
+
+/** 店铺 表单 */
+defineOptions({ name: 'ShopForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  name: undefined,
+  status: undefined,
+  merchantId: undefined
+})
+const formRules = reactive({
+  name: [{ required: true, message: '店铺名称不能为空', trigger: 'blur' }],
+  status: [{ required: true, message: '店铺状态不能为空', trigger: 'blur' }],
+  merchantId: [{ required: true, message: '商户id不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await ShopApi.getShop(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as ShopApi.ShopVO
+    if (formType.value === 'create') {
+      await ShopApi.createShop(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await ShopApi.updateShop(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    name: undefined,
+    status: undefined,
+    merchantId: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 211 - 0
src/views/system/sale/shop/index.vue

@@ -0,0 +1,211 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="店铺名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入店铺名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="店铺状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择店铺状态"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="商户id" prop="merchantId">
+        <el-input
+          v-model="queryParams.merchantId"
+          placeholder="请输入商户id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['sale:shop:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['sale:shop:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="店铺id" align="center" prop="id" />
+      <el-table-column label="店铺名称" align="center" prop="name" />
+      <el-table-column label="店铺状态" align="center" prop="status" />
+      <el-table-column label="商户id" align="center" prop="merchantId" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['sale:shop:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['sale:shop:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <ShopForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { ShopApi, ShopVO } from '@/api/system/sale/shop'
+import ShopForm from './ShopForm.vue'
+
+/** 店铺 列表 */
+defineOptions({ name: 'Shop' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<ShopVO[]>([]) // 列表的数据
+// 列表的总页数
+const total = ref(0)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  name: undefined,
+  status: undefined,
+  merchantId: undefined,
+  createTime: []
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await ShopApi.getShopPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await ShopApi.deleteShop(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await ShopApi.exportShop(queryParams)
+    download.excel(data, '店铺.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 92 - 0
src/views/system/sale/shopstatus/ShopStatusForm.vue

@@ -0,0 +1,92 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入名称" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { ShopStatusApi, ShopStatusVO } from '@/api/system/sale/shopstatus'
+
+/** 店铺状态 表单 */
+defineOptions({ name: 'ShopStatusForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  name: undefined
+})
+const formRules = reactive({
+  name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await ShopStatusApi.getShopStatus(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as ShopStatusApi.ShopStatusVO
+    if (formType.value === 'create') {
+      await ShopStatusApi.createShopStatus(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await ShopStatusApi.updateShopStatus(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    name: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 193 - 0
src/views/system/sale/shopstatus/index.vue

@@ -0,0 +1,193 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入名称"
+          clearable
+          @keyup.enter="handleQuery"
+          
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['sale:shop-status:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['sale:shop-status:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="名称" align="center" prop="name" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['sale:shop-status:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['sale:shop-status:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <ShopStatusForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { ShopStatusApi, ShopStatusVO } from '@/api/system/sale/shopstatus'
+import ShopStatusForm from './ShopStatusForm.vue'
+
+/** 店铺状态 列表 */
+defineOptions({ name: 'ShopStatus' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<ShopStatusVO[]>([]) // 列表的数据
+// 列表的总页数
+const total = ref(0)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  name: undefined,
+  createTime: []
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await ShopStatusApi.getShopStatusPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await ShopStatusApi.deleteShopStatus(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await ShopStatusApi.exportShopStatus(queryParams)
+    download.excel(data, '店铺状态.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>
+<style lang="scss" scoped>
+  ::v-deep .el-form-item__label {
+    width: auto !important;
+  }
+</style>