一些页面实现
This commit is contained in:
@@ -4,7 +4,7 @@ NODE_ENV=production
|
||||
VITE_DEV=false
|
||||
|
||||
# 请求路径
|
||||
VITE_BASE_URL='http://localhost:48080'
|
||||
VITE_BASE_URL='https://www.cdsrh.top'
|
||||
|
||||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
|
||||
VITE_UPLOAD_TYPE=server
|
||||
@@ -22,7 +22,7 @@ VITE_DROP_CONSOLE=true
|
||||
VITE_SOURCEMAP=false
|
||||
|
||||
# 打包路径
|
||||
VITE_BASE_PATH=/
|
||||
VITE_BASE_PATH=/kfc/
|
||||
|
||||
# 输出路径
|
||||
VITE_OUT_DIR=dist-prod
|
||||
|
@@ -14,7 +14,13 @@
|
||||
content="芋道管理系统 基于 vue3 + CompositionAPI + typescript + vite3 + element plus 的后台开源免费管理系统!"
|
||||
/>
|
||||
<title>%VITE_APP_TITLE%</title>
|
||||
<script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=6fe46798cd1e0f55d95ffc3a993e29ac&plugin=AMap.Geolocation"></script>
|
||||
<script>
|
||||
// 定义SDK加载完成的回调
|
||||
window.onAmapLoaded = function() {}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<style>
|
||||
|
6
package-lock.json
generated
6
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "yudao-ui-admin-vue3",
|
||||
"version": "2.5.0-snapshot",
|
||||
"version": "2.6.1-snapshot",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "yudao-ui-admin-vue3",
|
||||
"version": "2.5.0-snapshot",
|
||||
"version": "2.6.1-snapshot",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
@@ -20,7 +20,7 @@
|
||||
"@wangeditor/editor-for-vue": "^5.1.10",
|
||||
"@zxcvbn-ts/core": "^3.0.4",
|
||||
"animate.css": "^4.1.1",
|
||||
"axios": "^1.6.8",
|
||||
"axios": "1.9.0",
|
||||
"benz-amr-recorder": "^1.1.5",
|
||||
"bpmn-js-token-simulation": "^0.36.0",
|
||||
"camunda-bpmn-moddle": "^7.0.1",
|
||||
|
@@ -47,4 +47,11 @@ export const AgentOrderApi = {
|
||||
exportAgentOrder: async (params) => {
|
||||
return await request.download({ url: `/kfc/agent-order/export-excel`, params })
|
||||
},
|
||||
|
||||
submitOrder: async (data:any) => {
|
||||
return await request.post({
|
||||
url: `/kfc/agent-order/submit`, data
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -55,4 +55,16 @@ export const ProductApi = {
|
||||
exportProduct: async (params) => {
|
||||
return await request.download({ url: `/kfc/product/export-excel`, params })
|
||||
},
|
||||
//查询kfc商品分类
|
||||
getKFCProductCategory: async()=>{
|
||||
return await request.get({ url: `/kfc/product/get/outProduct/sort` })
|
||||
},
|
||||
//查询kfc商品表单
|
||||
getKFCProductForm: async(id:string)=>{
|
||||
return await request.get({ url: `/kfc/product/get/outProduct/form?id=${id}`})
|
||||
},
|
||||
//查询kfc商品规格详情
|
||||
getKFCProductDetail: async(linkId:string)=>{
|
||||
return await request.get({ url: `/kfc/product/get/outProduct/detail?linkId=${linkId}` })
|
||||
}
|
||||
}
|
||||
|
22
src/api/kfc/store/index.ts
Normal file
22
src/api/kfc/store/index.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
/** 门店基本信息信息 */
|
||||
export interface KfcStore {
|
||||
storename:string;//门店名称
|
||||
address:string;//门店地址
|
||||
distance:string;//门店描述
|
||||
tel:string;//联系电话
|
||||
}
|
||||
|
||||
// 门店信息 API
|
||||
export const StroeApi = {
|
||||
// 查询门店基本信息列表
|
||||
getStoreList: async (lon: number,lat:number) => {
|
||||
return await request.get({ url: `/store/list?lon=${lon}&lat=${lat}`})
|
||||
},
|
||||
|
||||
getStoreListByCity: async(city:string)=>{
|
||||
return await request.get({ url: `/store/city-list?city=${city}`})
|
||||
},
|
||||
|
||||
}
|
32
src/types/amap.d.ts
vendored
Normal file
32
src/types/amap.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
interface Window {
|
||||
AMap: {
|
||||
// 声明AMap的核心方法和类
|
||||
plugin: (
|
||||
pluginName: string | string[],
|
||||
callback: () => void
|
||||
) => void;
|
||||
Geolocation: new (options: AMapGeolocationOptions) => AMapGeolocation;
|
||||
};
|
||||
onAmapLoaded: () => void;
|
||||
}
|
||||
|
||||
// 定位配置选项类型
|
||||
interface AMapGeolocationOptions {
|
||||
enableHighAccuracy?: boolean;
|
||||
timeout?: number;
|
||||
convert?: boolean;
|
||||
buttonPosition?: string;
|
||||
buttonOffset?: any;
|
||||
zoomToAccuracy?: boolean;
|
||||
}
|
||||
|
||||
// 定位实例的方法类型
|
||||
interface AMapGeolocation {
|
||||
getCityInfo: (callback: (status: string, result: any) => void) => void;
|
||||
getCurrentPosition: (callback: (status: string, result: any) => void) => void;
|
||||
destroy: () => void;
|
||||
}
|
||||
|
||||
// 确保TypeScript将此文件视为模块
|
||||
export {};
|
@@ -37,8 +37,22 @@
|
||||
<el-input v-model="formData.triggerCondition" placeholder="请输入触发条件" />
|
||||
</el-form-item>
|
||||
<el-form-item label="接收用户" prop="receiveUserIds">
|
||||
<el-input v-model="formData.receiveUserIds" placeholder="请输入接收用户,多个用户用','隔开'" />
|
||||
</el-form-item>
|
||||
<el-select
|
||||
v-model="formData.receiveUserIds"
|
||||
placeholder="请选择接收用户"
|
||||
@click="getSimpleUserList()"
|
||||
multiple
|
||||
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in simpleUserList"
|
||||
:key="dict.id"
|
||||
:label="dict.nickname"
|
||||
:value="dict.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="通知方式" prop="notificationWay">
|
||||
<el-checkbox-group v-model="formData.notificationWay">
|
||||
<el-checkbox
|
||||
@@ -69,6 +83,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { getIntDictOptions, getStrDictOptions, DICT_TYPE } from '@/utils/dict'
|
||||
import * as UserApi from '@/api/system/user'
|
||||
import { AlarmConfigApi, AlarmConfig } from '@/api/kfc/alarm/alarmconfig'
|
||||
|
||||
/** 报警配置 表单 */
|
||||
@@ -124,14 +139,13 @@ const submitForm = async () => {
|
||||
// 校验表单
|
||||
await formRef.value.validate()
|
||||
const submitData = { ...formData.value }; // 复制一份数据,避免修改原表单
|
||||
if (submitData.receiveUserIds) {
|
||||
// 分割字符串为数组,并转换为数字类型
|
||||
submitData.receiveUserIds = formData.value.receiveUserIds
|
||||
.split(',')
|
||||
.map(id => Number(id.trim())) // 去除空格并转为数字
|
||||
.filter(id => !isNaN(id)); // 过滤无效数字
|
||||
if (Array.isArray(submitData.receiveUserIds)) {
|
||||
// 确保是数字数组(过滤无效值)
|
||||
submitData.receiveUserIds = submitData.receiveUserIds
|
||||
.map(id => Number(id))
|
||||
.filter(id => !isNaN(id));
|
||||
} else {
|
||||
// 空值处理:确保后端接收数组类型(而非undefined)
|
||||
// 兜底:确保始终是数组类型
|
||||
submitData.receiveUserIds = [];
|
||||
}
|
||||
// 提交请求
|
||||
@@ -152,7 +166,11 @@ const submitForm = async () => {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
const simpleUserList=ref()
|
||||
|
||||
const getSimpleUserList =async ()=>{
|
||||
simpleUserList.value = await UserApi.getSimpleUserList()
|
||||
}
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
|
@@ -239,7 +239,7 @@ const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await AlarmConfigApi.getAlarmConfigPage(queryParams)
|
||||
console.log(data)
|
||||
// console.log(data)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
|
138
src/views/kfc/product/KFCProductForm.vue
Normal file
138
src/views/kfc/product/KFCProductForm.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible" width="80%">
|
||||
<div v-loading="formLoading" class="loading-container">
|
||||
<!-- 基础信息表格 -->
|
||||
<el-table :data="baseInfoTableData" border style="margin-bottom: 20px;">
|
||||
<el-table-column prop="label" label="基础信息" width="180" align="center" />
|
||||
<el-table-column prop="value" label="详情" align="left" />
|
||||
</el-table>
|
||||
|
||||
<!-- 餐品分类表格 -->
|
||||
<el-table
|
||||
:data="categoryTableData"
|
||||
border
|
||||
style="margin-bottom: 10px;"
|
||||
row-key="round"
|
||||
>
|
||||
<el-table-column prop="roundNameCn" label="分类名称" width="150" />
|
||||
<el-table-column prop="round" label="排序" width="80" align="center" />
|
||||
<el-table-column label="餐品列表" align="left">
|
||||
<template #default="scope">
|
||||
<el-table
|
||||
:data="scope.row.condimentItemList"
|
||||
border
|
||||
size="small"
|
||||
style="width: 100%;"
|
||||
row-key="linkId"
|
||||
>
|
||||
<el-table-column prop="showNameCn" label="显示名称" width="180" />
|
||||
<el-table-column prop="nameCn" label="商品名称" width="180" />
|
||||
<el-table-column
|
||||
prop="price"
|
||||
label="价格"
|
||||
width="100"
|
||||
align="right"
|
||||
:formatter="(row) => row.price === 0 ? '0' : (row.price / 100).toFixed(2)"
|
||||
/>
|
||||
<el-table-column prop="quantity" label="数量" width="80" align="center" />
|
||||
<el-table-column prop="linkId" label="商品ID" width="150" />
|
||||
<el-table-column prop="imageUrl" label="图片URL">
|
||||
<template #default="itemScope">
|
||||
<el-input
|
||||
v-model="itemScope.row.imageUrl"
|
||||
disabled
|
||||
style="width: 300px;"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">关 闭</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ProductApi } from '@/api/kfc/product'
|
||||
|
||||
/** 商品详情表格展示组件 */
|
||||
defineOptions({ name: 'ProductDetailTable' })
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
// 状态管理
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('商品详情')
|
||||
const formLoading = ref(false)
|
||||
|
||||
// 原始数据
|
||||
const formData = ref({
|
||||
linkId: '',
|
||||
disabledStatus: 0,
|
||||
saleFlag: 'Y',
|
||||
condimentRoundList: [] as Array<{
|
||||
roundNameCn: string
|
||||
round: number
|
||||
condimentItemList: Array<{
|
||||
linkId: string
|
||||
imageUrl: string
|
||||
showNameCn: string
|
||||
nameCn: string
|
||||
price: number
|
||||
quantity: number
|
||||
mealdealId: number
|
||||
itemType: number
|
||||
}>
|
||||
}>
|
||||
})
|
||||
|
||||
// 基础信息表格数据(转换为键值对格式)
|
||||
const baseInfoTableData = computed(() => [
|
||||
{ label: '关联ID', value: formData.value.linkId },
|
||||
{
|
||||
label: '禁用状态',
|
||||
value: formData.value.disabledStatus === 0 ? '启用' : '禁用'
|
||||
},
|
||||
{
|
||||
label: '销售状态',
|
||||
value: formData.value.saleFlag === 'Y' ? '在售' : '下架'
|
||||
}
|
||||
])
|
||||
|
||||
// 分类表格数据(直接使用原始数组)
|
||||
const categoryTableData = computed(() => formData.value.condimentRoundList)
|
||||
|
||||
/** 打开弹窗并加载数据 */
|
||||
const open = async (linkId: string) => {
|
||||
dialogVisible.value = true
|
||||
formLoading.value = true
|
||||
try {
|
||||
// 调用接口获取数据(假设接口返回格式为 {code:0, data: {disabledStatus, ...}})
|
||||
const response = await ProductApi.getKFCProductDetail(linkId)
|
||||
// if (response.code === 0) {
|
||||
formData.value = { ...formData.value, ...response}
|
||||
// } else {
|
||||
// message.error(`加载失败:${response.msg || '未知错误'}`)
|
||||
// }
|
||||
} catch (error) {
|
||||
message.error(t('common.loadFail'))
|
||||
console.error('数据加载失败:', error)
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.loading-container {
|
||||
min-height: 300px;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
@@ -36,7 +36,7 @@
|
||||
<el-form-item label="商品价格" prop="price">
|
||||
<el-input v-model="formData.price" placeholder="请输入商品价格" />
|
||||
</el-form-item>
|
||||
<el-form-item label="中文显示名称" prop="showNameCn">
|
||||
<el-form-item label="名称" prop="showNameCn">
|
||||
<el-input v-model="formData.showNameCn" placeholder="请输入中文显示名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单品标记" prop="singleFlag">
|
||||
|
@@ -223,8 +223,15 @@
|
||||
:formatter="dateFormatter"
|
||||
width="180px"
|
||||
/>
|
||||
<el-table-column label="操作" align="center" min-width="120px">
|
||||
<el-table-column label="操作" align="center" min-width="180px">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@click="openKFCForm(scope.row.linkId)"
|
||||
>
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@@ -255,6 +262,7 @@
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<ProductForm ref="formRef" @success="getList" />
|
||||
<KFCProductForm ref="KFCformRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -264,6 +272,7 @@ import { dateFormatter } from '@/utils/formatTime'
|
||||
import download from '@/utils/download'
|
||||
import { ProductApi, Product } from '@/api/kfc/product'
|
||||
import ProductForm from './ProductForm.vue'
|
||||
import KFCProductForm from './KFCProductForm.vue'
|
||||
|
||||
/** 商品基本信息 列表 */
|
||||
defineOptions({ name: 'Product' })
|
||||
@@ -325,6 +334,10 @@ const formRef = ref()
|
||||
const openForm = (type: string, id?: number) => {
|
||||
formRef.value.open(type, id)
|
||||
}
|
||||
const KFCformRef=ref()
|
||||
const openKFCForm=(id:number)=>{
|
||||
KFCformRef.value.open(id)
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
|
439
src/views/kfc/store/index.vue
Normal file
439
src/views/kfc/store/index.vue
Normal file
@@ -0,0 +1,439 @@
|
||||
<template>
|
||||
<div class="store-page">
|
||||
<!-- 页面标题与搜索框 -->
|
||||
<div class="page-header">
|
||||
<h1>附近门店</h1>
|
||||
<p class="sub-title">为您展示周边可用门店信息</p>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<div class="search-box">
|
||||
<el-input
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入门店名称搜索..."
|
||||
prefix-icon="Search"
|
||||
clearable
|
||||
size="medium"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 门店列表 -->
|
||||
<div class="store-list" v-loading="loading">
|
||||
<div
|
||||
v-for="(store, index) in filteredStoreList"
|
||||
:key="index"
|
||||
class="store-card"
|
||||
>
|
||||
<div class="store-info">
|
||||
<h3 class="store-name">
|
||||
{{ store.storename }}
|
||||
<span class="distance-tag">距离:{{ store.distance || '未知'}}</span>
|
||||
</h3>
|
||||
<div class="store-detail">
|
||||
<p class="address">
|
||||
<el-icon class="icon"><Location /></el-icon>
|
||||
{{ store.address }}
|
||||
</p>
|
||||
<p class="tel">
|
||||
<el-icon class="icon"><Phone /></el-icon>
|
||||
{{ store.tel }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="store-actions">
|
||||
<el-button type="primary" @click="handleSelectStore(store)">
|
||||
选择此门店并提交订单
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div class="empty-state" v-if="!loading && filteredStoreList.length === 0">
|
||||
<el-empty :description="getEmptyDescription()" />
|
||||
<el-button
|
||||
type="text"
|
||||
@click="retryGetLocation"
|
||||
v-if="showRetryButton"
|
||||
>
|
||||
重试获取位置
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 手动输入code的弹窗 -->
|
||||
<el-dialog
|
||||
v-model="showCodeDialog"
|
||||
title="激活码"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-input
|
||||
v-model="inputCode"
|
||||
placeholder="请输入激活码"
|
||||
@keyup.enter="confirmCode"
|
||||
/>
|
||||
<template #footer>
|
||||
<el-button @click="showCodeDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmCode">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 手动选择城市弹窗 -->
|
||||
<el-dialog v-model="showCitySelectDialog" title="选择城市">
|
||||
<el-input
|
||||
v-model="cityName"
|
||||
placeholder="请输入城市名称"
|
||||
@keyup.enter="confirmCity"
|
||||
/>
|
||||
<template #footer>
|
||||
<el-button @click="showCitySelectDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmCity">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { StroeApi, KfcStore } from '@/api/kfc/store'
|
||||
import { AgentOrderApi } from '@/api/kfc/finance/agentorder'
|
||||
import { ElMessage, ElLoading } from 'element-plus'
|
||||
import { Location, Phone, Search } from '@element-plus/icons-vue'
|
||||
|
||||
// 路由相关
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
// 状态管理
|
||||
const loading = ref(false)
|
||||
const storeList = ref<KfcStore[]>([])
|
||||
const searchKeyword = ref('')
|
||||
const userLocation = ref<{ lon: number, lat: number } | null>(null)
|
||||
const cityName = ref('')
|
||||
const selectedStore = ref<KfcStore | null>(null) // 选中的门店
|
||||
|
||||
// code相关状态
|
||||
const systemCode = ref('') // 系统生成的固定code
|
||||
const showCodeDialog = ref(false)
|
||||
const inputCode = ref('')
|
||||
const currentCode = ref('') // 最终有效的code
|
||||
|
||||
// 错误状态
|
||||
const emptyDescription = ref('正在获取您的位置...')
|
||||
const showRetryButton = ref(false)
|
||||
const showCitySelectDialog = ref(false)
|
||||
|
||||
// 高德地图定位实例
|
||||
let geolocation: any = null
|
||||
|
||||
// 过滤门店列表
|
||||
const filteredStoreList = computed(() => {
|
||||
if (!searchKeyword.value.trim()) {
|
||||
return storeList.value
|
||||
}
|
||||
const keyword = searchKeyword.value.trim().toLowerCase()
|
||||
return storeList.value.filter(store =>
|
||||
store.storename?.toLowerCase().includes(keyword)
|
||||
)
|
||||
})
|
||||
|
||||
// 空状态描述
|
||||
const getEmptyDescription = () => {
|
||||
if (searchKeyword.value.trim()) {
|
||||
return `未找到包含"${searchKeyword.value}"的门店`
|
||||
}
|
||||
return emptyDescription.value
|
||||
}
|
||||
|
||||
// 页面挂载时处理code
|
||||
onMounted(() => {
|
||||
handleCodeLogic()
|
||||
})
|
||||
|
||||
// 处理code逻辑
|
||||
const handleCodeLogic = () => {
|
||||
const urlCode = route.query.code as string
|
||||
if (urlCode) {
|
||||
currentCode.value = urlCode
|
||||
initLocationAndStore()
|
||||
return
|
||||
}
|
||||
|
||||
if (systemCode.value) {
|
||||
router.replace({ ...route, query: { ...route.query, code: systemCode.value } })
|
||||
currentCode.value = systemCode.value
|
||||
initLocationAndStore()
|
||||
return
|
||||
}
|
||||
|
||||
showCodeDialog.value = true
|
||||
}
|
||||
|
||||
// 确认用户输入的code
|
||||
const confirmCode = () => {
|
||||
if (!inputCode.value.trim()) {
|
||||
ElMessage.warning('激活码不能为空')
|
||||
return
|
||||
}
|
||||
router.replace({ ...route, query: { ...route.query, code: inputCode.value.trim() } })
|
||||
currentCode.value = inputCode.value.trim()
|
||||
showCodeDialog.value = false
|
||||
initLocationAndStore()
|
||||
}
|
||||
|
||||
// 初始化定位和门店
|
||||
const initLocationAndStore = () => {
|
||||
console.log('当前code:', currentCode.value)
|
||||
if (window.AMap) {
|
||||
initAmapLocation()
|
||||
} else {
|
||||
emptyDescription.value = '地图服务加载中...'
|
||||
window.onAmapLoaded = () => initAmapLocation()
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化高德定位
|
||||
const initAmapLocation = () => {
|
||||
window.AMap.plugin('AMap.Geolocation', () => {
|
||||
geolocation = new AMap.Geolocation({
|
||||
enableHighAccuracy: true,
|
||||
timeout: 8000,
|
||||
convert: true,
|
||||
zoomToAccuracy: false,
|
||||
buttonPosition: 'RB'
|
||||
})
|
||||
|
||||
geolocation.getCityInfo((status: string, result: any) => {
|
||||
if (status === 'complete' && result.city) {
|
||||
cityName.value = result.city
|
||||
}
|
||||
})
|
||||
|
||||
geolocation.getCurrentPosition((status: string, result: any) => {
|
||||
handleAmapResult(status, result)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 处理定位结果
|
||||
const handleAmapResult = (status: string, result: any) => {
|
||||
loading.value = true
|
||||
if (status === 'complete' && result.position) {
|
||||
userLocation.value = {
|
||||
lon: result.position.lng,
|
||||
lat: result.position.lat
|
||||
}
|
||||
fetchStoreList()
|
||||
} else {
|
||||
handleLocationError(result)
|
||||
}
|
||||
}
|
||||
|
||||
// 定位失败处理
|
||||
const handleLocationError = (result: any) => {
|
||||
loading.value = false
|
||||
showRetryButton.value = true
|
||||
|
||||
switch (result.info) {
|
||||
case 'PERMISSION_DENIED':
|
||||
emptyDescription.value = '您拒绝了定位授权,请在设置中开启'
|
||||
break
|
||||
case 'POSITION_UNAVAILABLE':
|
||||
emptyDescription.value = '无法获取位置信息'
|
||||
break
|
||||
case 'TIMEOUT':
|
||||
emptyDescription.value = '定位超时'
|
||||
break
|
||||
default:
|
||||
emptyDescription.value = `定位失败:${result.info || '未知错误'}`
|
||||
}
|
||||
|
||||
if (cityName.value) {
|
||||
showCitySelectDialog.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 获取门店列表
|
||||
const fetchStoreList = async () => {
|
||||
if (!userLocation.value) return
|
||||
|
||||
try {
|
||||
const response = await StroeApi.getStoreList(
|
||||
userLocation.value.lon,
|
||||
userLocation.value.lat
|
||||
)
|
||||
storeList.value = response || []
|
||||
emptyDescription.value = storeList.value.length === 0
|
||||
? '未查询到附近门店'
|
||||
: ''
|
||||
} catch (error) {
|
||||
emptyDescription.value = '获取门店失败,请重试'
|
||||
showRetryButton.value = true
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重试定位
|
||||
const retryGetLocation = () => {
|
||||
storeList.value = []
|
||||
emptyDescription.value = '正在重新获取位置...'
|
||||
showRetryButton.value = false
|
||||
initAmapLocation()
|
||||
}
|
||||
|
||||
// 确认城市
|
||||
const confirmCity = () => {
|
||||
if (!cityName.value) {
|
||||
ElMessage.warning('请输入城市名称')
|
||||
return
|
||||
}
|
||||
showCitySelectDialog.value = false
|
||||
loading.value = true
|
||||
fetchStoreByCity(cityName.value)
|
||||
}
|
||||
|
||||
// 按城市获取门店
|
||||
const fetchStoreByCity = async (city: string) => {
|
||||
try {
|
||||
const response = await StroeApi.getStoreListByCity(city)
|
||||
storeList.value = response || []
|
||||
emptyDescription.value = storeList.value.length === 0
|
||||
? `未查询到${city}的门店`
|
||||
: ''
|
||||
} catch (error) {
|
||||
emptyDescription.value = '获取门店失败,请重试'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 选择门店并提交订单
|
||||
const handleSelectStore = async (store: KfcStore) => {
|
||||
selectedStore.value = store
|
||||
// 校验code是否存在(理论上此时code必存在,做双重保险)
|
||||
if (!currentCode.value) {
|
||||
ElMessage.error('缺少必要参数code,请刷新页面重试')
|
||||
return
|
||||
}
|
||||
// 调用提交订单接口
|
||||
await submitOrder()
|
||||
}
|
||||
|
||||
// 提交订单接口(核心:传入code和门店参数)
|
||||
const submitOrder = async () => {
|
||||
if (!selectedStore.value) return
|
||||
|
||||
const loadingInstance = ElLoading.service({
|
||||
lock: true,
|
||||
text: '提交订单中...',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
|
||||
try {
|
||||
// 构造订单参数:包含code和门店信息
|
||||
const orderParams = {
|
||||
orderNo: currentCode.value, // 传入code
|
||||
storeName: selectedStore.value.storename, // 门店名称
|
||||
}
|
||||
|
||||
// 调用订单接口
|
||||
const result = await AgentOrderApi.submitOrder(orderParams)
|
||||
console.log(result.mealCode)
|
||||
|
||||
if (result.agentOrderNo) {
|
||||
ElMessage.success(`订单提交成功!订单号:${result.agentOrderNo}`)
|
||||
alert("下单成功,取餐码:"+result.mealCode)
|
||||
// 可跳转至订单详情页
|
||||
// router.push(`/order/detail?orderNo=${result.orderNo}`)
|
||||
} else {
|
||||
ElMessage.error(`提交失败:${result.message || '未知错误'}`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('订单提交失败', error)
|
||||
ElMessage.error('网络异常,订单提交失败,请重试')
|
||||
} finally {
|
||||
loadingInstance.close()
|
||||
}
|
||||
}
|
||||
|
||||
// 页面卸载时销毁定位实例
|
||||
onUnmounted(() => {
|
||||
if (geolocation) {
|
||||
geolocation.destroy()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.store-page {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
/* 搜索框样式 */
|
||||
.search-box {
|
||||
margin-top: 15px;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.store-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
max-height: calc(100vh - 220px); /* 预留搜索框高度 */
|
||||
overflow-y: auto;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.store-card {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.store-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.store-name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.distance-tag {
|
||||
font-size: 14px;
|
||||
color: #409eff;
|
||||
background-color: #ecf5ff;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.store-detail p {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: 8px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
grid-column: 1 / -1;
|
||||
padding: 60px 0;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
@@ -31,13 +31,14 @@
|
||||
// "vite-plugin-svg-icons/client"
|
||||
],
|
||||
"outDir": "target", // 请保留这个属性,防止tsconfig.json文件报错
|
||||
"typeRoots": ["./node_modules/@types/", "./types"]
|
||||
"typeRoots": ["./node_modules/@types/", "./types","./src/types"]
|
||||
},
|
||||
"include": [
|
||||
"src",
|
||||
"types/**/*.d.ts",
|
||||
"src/types/auto-imports.d.ts",
|
||||
"src/types/auto-components.d.ts"
|
||||
"src/types/auto-components.d.ts",
|
||||
"src/types/**/*.d.ts"
|
||||
],
|
||||
"exclude": ["dist", "target", "node_modules"]
|
||||
}
|
||||
|
Reference in New Issue
Block a user