|
|
@@ -7,24 +7,14 @@
|
|
|
<div class="right-panel">
|
|
|
<el-radio-group v-model="filters.service" size="default" @change="handleSearch">
|
|
|
<el-radio-button value="">全部类型</el-radio-button>
|
|
|
- <el-radio-button v-for="item in serviceOptions" :key="item.id" :value="item.id">{{ item.name }}</el-radio-button>
|
|
|
+ <el-radio-button v-for="item in serviceOptions" :key="item.id" :value="item.id">{{ item.name
|
|
|
+ }}</el-radio-button>
|
|
|
</el-radio-group>
|
|
|
- <el-input
|
|
|
- v-model="filters.content"
|
|
|
- placeholder="订单号/商户/宠主/手机号"
|
|
|
- class="search-input"
|
|
|
- prefix-icon="Search"
|
|
|
- clearable
|
|
|
- @clear="handleSearch"
|
|
|
- @keyup.enter="handleSearch"
|
|
|
- />
|
|
|
+ <el-input v-model="filters.content" placeholder="订单号/商户/宠主/手机号" class="search-input" prefix-icon="Search"
|
|
|
+ clearable @clear="handleSearch" @keyup.enter="handleSearch" />
|
|
|
<el-button type="primary" icon="Search" @click="handleSearch">查询</el-button>
|
|
|
- <el-button
|
|
|
- v-hasPermi="['order:management:export']"
|
|
|
- type="success"
|
|
|
- icon="Download"
|
|
|
- @click="handleExport"
|
|
|
- >导出Excel</el-button>
|
|
|
+ <el-button v-hasPermi="['order:management:export']" type="success" icon="Download"
|
|
|
+ @click="handleExport">导出Excel</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -39,17 +29,20 @@
|
|
|
</el-tabs>
|
|
|
</template>
|
|
|
|
|
|
- <el-table :data="tableData" style="width: 100%" v-loading="loading" :header-cell-style="{ background: '#f5f7fa' }">
|
|
|
+ <el-table :data="tableData" style="width: 100%" v-loading="loading"
|
|
|
+ :header-cell-style="{ background: '#f5f7fa' }">
|
|
|
<el-table-column prop="code" label="订单号" width="170" fixed="left" />
|
|
|
|
|
|
<el-table-column label="服务类型" width="190">
|
|
|
<template #default="{ row }">
|
|
|
<div class="service-type-cell">
|
|
|
<el-tag>{{ getServiceName(row.service) }}</el-tag>
|
|
|
- <el-tag v-if="getServiceModeTag(row)" class="sub-tag" type="warning" effect="plain">{{ getServiceModeTag(row) }}</el-tag>
|
|
|
- <el-tag v-if="getServiceOrderTypeTag(row)" class="sub-tag" :type="getServiceOrderTypeTag(row).type" effect="dark">{{
|
|
|
- getServiceOrderTypeTag(row).label
|
|
|
- }}</el-tag>
|
|
|
+ <el-tag v-if="getServiceModeTag(row)" class="sub-tag" type="warning" effect="plain">{{
|
|
|
+ getServiceModeTag(row) }}</el-tag>
|
|
|
+ <el-tag v-if="getServiceOrderTypeTag(row)" class="sub-tag" :type="getServiceOrderTypeTag(row).type"
|
|
|
+ effect="dark">{{
|
|
|
+ getServiceOrderTypeTag(row).label
|
|
|
+ }}</el-tag>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
@@ -111,25 +104,25 @@
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
|
|
|
- <el-table-column label="履约信息" width="140">
|
|
|
+ <el-table-column label="履约者" width="120">
|
|
|
<template #default="{ row }">
|
|
|
- <div v-if="row.fulfillerName" class="fulfiller-info">
|
|
|
- <span class="fulfiller-name">{{ row.fulfillerName }}</span>
|
|
|
- <span class="fulfiller-fee" v-if="row.price !== null && row.price !== undefined">¥{{ row.price / 100.0 }}</span>
|
|
|
- </div>
|
|
|
+ <span v-if="row.fulfillerName" style="font-weight: 500; color: #333;">{{ row.fulfillerName }}</span>
|
|
|
<span v-else class="text-gray">暂未指派</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
|
|
|
+
|
|
|
<el-table-column label="操作" width="200" fixed="right">
|
|
|
<template #default="{ row }">
|
|
|
<div class="op-cell">
|
|
|
<el-button link type="primary" size="small" @click="handleDetail(row)">详情</el-button>
|
|
|
<!-- <el-button v-if="row.status === 0" link type="success" size="small" @click="openDispatchDialog(row)">派单</el-button>-->
|
|
|
<!-- <el-button v-if="![0, 4].includes(row.status)" link type="warning" size="small" @click="openDispatchDialog(row)">重新派单</el-button>-->
|
|
|
- <el-button v-if="[0, 1].includes(row.status)" link type="danger" size="small" @click="handleCancel(row)">取消</el-button>
|
|
|
+ <el-button v-if="[0, 1].includes(row.status)" link type="danger" size="small"
|
|
|
+ @click="handleCancel(row)">取消</el-button>
|
|
|
|
|
|
- <el-dropdown v-if="[3, 4].includes(row.status)" trigger="click" @command="(cmd) => handleCommand(cmd, row)">
|
|
|
+ <el-dropdown v-if="[3, 4].includes(row.status)" trigger="click"
|
|
|
+ @command="(cmd) => handleCommand(cmd, row)">
|
|
|
<span class="el-dropdown-link">
|
|
|
更多<el-icon class="el-icon--right">
|
|
|
<ArrowDown />
|
|
|
@@ -137,10 +130,10 @@
|
|
|
</span>
|
|
|
<template #dropdown>
|
|
|
<el-dropdown-menu>
|
|
|
-<!-- <el-dropdown-item v-if="row.status === 3" command="complete">确认完成</el-dropdown-item>-->
|
|
|
- <el-dropdown-item v-if="row.status === 4 && getServiceMode(row.service) == 0" command="care_summary" v-hasPermi="['order:management:nursingSummary']">护理小结</el-dropdown-item>
|
|
|
- <el-dropdown-item command="reward" v-hasPermi="['order:management:reward']">奖惩</el-dropdown-item>
|
|
|
- <el-dropdown-item command="remark" v-hasPermi="['order:management:remark']">备注</el-dropdown-item>
|
|
|
+ <!-- <el-dropdown-item v-if="row.status === 3" command="complete">确认完成</el-dropdown-item>-->
|
|
|
+ <el-dropdown-item v-if="row.status === 4 && getServiceMode(row.service) == 0" command="care_summary"
|
|
|
+ v-hasPermi="['order:management:nursingSummary']">护理小结</el-dropdown-item>
|
|
|
+
|
|
|
</el-dropdown-menu>
|
|
|
</template>
|
|
|
</el-dropdown>
|
|
|
@@ -150,48 +143,32 @@
|
|
|
</el-table>
|
|
|
|
|
|
<div class="pagination-container">
|
|
|
- <el-pagination
|
|
|
- v-model:current-page="pagination.current"
|
|
|
- v-model:page-size="pagination.size"
|
|
|
- :page-sizes="[10, 20, 50, 100]"
|
|
|
- layout="total, sizes, prev, pager, next, jumper"
|
|
|
- :total="pagination.total"
|
|
|
- @size-change="handleSizeChange"
|
|
|
- @current-change="handleCurrentChange"
|
|
|
- />
|
|
|
+ <el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.size"
|
|
|
+ :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total"
|
|
|
+ @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
|
|
</div>
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 组件 -->
|
|
|
- <OrderDetailDrawer
|
|
|
- v-model:visible="detailVisible"
|
|
|
- :order="currentOrder"
|
|
|
- @dispatch="openDispatchDialog"
|
|
|
- @cancel="handleCancel"
|
|
|
- @command="handleCommand"
|
|
|
- @care-summary="openCareSummary"
|
|
|
- />
|
|
|
+ <OrderDetailDrawer v-model:visible="detailVisible" :order="currentOrder" @dispatch="openDispatchDialog"
|
|
|
+ @cancel="handleCancel" @command="handleCommand" @care-summary="openCareSummary" />
|
|
|
|
|
|
- <DispatchDialog v-model:visible="dispatchDialogVisible" :order="currentDispatchOrder" @submit="handleDispatchSubmit" />
|
|
|
+ <DispatchDialog v-model:visible="dispatchDialogVisible" :order="currentDispatchOrder"
|
|
|
+ @submit="handleDispatchSubmit" />
|
|
|
|
|
|
<CareSummaryDrawer v-model:visible="careSummaryVisible" :order="careSummaryOrder" @submit="saveCareSummary" />
|
|
|
|
|
|
- <RewardDialog v-model:visible="rewardDialogVisible" :order="currentOperateRow" @submit="handleRewardSubmit" />
|
|
|
-
|
|
|
- <RemarkDialog v-model:visible="remarkDialogVisible" :order="currentOperateRow" @submit="handleRemarkSubmit" />
|
|
|
-
|
|
|
<PetDetailDrawer v-model:visible="petDetailVisible" :pet-id="currentPetId" />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, reactive, onMounted, nextTick, getCurrentInstance, toRefs } from 'vue';
|
|
|
+import { ref, reactive, onMounted, onUnmounted, nextTick, getCurrentInstance, toRefs } from 'vue';
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
import OrderDetailDrawer from './components/OrderDetailDrawer.vue';
|
|
|
import DispatchDialog from './components/DispatchDialog.vue';
|
|
|
import CareSummaryDrawer from './components/CareSummaryDrawer.vue';
|
|
|
-import RewardDialog from './components/RewardDialog.vue';
|
|
|
-import RemarkDialog from './components/RemarkDialog.vue';
|
|
|
+
|
|
|
import PetDetailDrawer from '@/components/PetDetailDrawer/index.vue';
|
|
|
import { listAllService } from '@/api/service/list/index';
|
|
|
import { listSubOrder, dispatchSubOrder, getSubOrderInfo, cancelSubOrder, remarkSubOrder, confirmSubOrder, nursingSummarySubOrder, exportSubOrder } from '@/api/order/subOrder/index';
|
|
|
@@ -226,10 +203,33 @@ const areaStationList = ref([]);
|
|
|
const areaStationMap = ref({});
|
|
|
const storeMap = ref({});
|
|
|
|
|
|
+let timer = null;
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
getServiceList();
|
|
|
getAreaStationList();
|
|
|
handleSearch();
|
|
|
+
|
|
|
+ timer = setInterval(() => {
|
|
|
+ listSubOrder({
|
|
|
+ pageNum: pagination.current,
|
|
|
+ pageSize: pagination.size,
|
|
|
+ service: filters.service !== '' ? filters.service : undefined,
|
|
|
+ status: filters.status !== '' ? Number(filters.status) : undefined,
|
|
|
+ content: filters.content || undefined
|
|
|
+ }).then((res) => {
|
|
|
+ tableData.value = res.rows || [];
|
|
|
+ pagination.total = res.total || 0;
|
|
|
+ loadStoresForRows(tableData.value);
|
|
|
+ }).catch(() => { });
|
|
|
+ }, 5000);
|
|
|
+});
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ if (timer) {
|
|
|
+ clearInterval(timer);
|
|
|
+ timer = null;
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
const getServiceList = () => {
|
|
|
@@ -408,40 +408,35 @@ const handleDetail = async (row) => {
|
|
|
orderNo: row?.code || row?.orderCode || row?.orderNo || row?.orderNumber || row?.no || '',
|
|
|
type: row?.typeCode || row?.type || typeCode,
|
|
|
serviceItem: getServiceName(row?.service) || row?.serviceName || row?.service || '',
|
|
|
- userAvatar: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
|
|
|
- address: '某小区5号楼2单元101',
|
|
|
+ userAvatar: row?.userAvatar || '',
|
|
|
+ address: row?.address || '',
|
|
|
groupBuyPackage: '',
|
|
|
- transportType: row.splitType || row.transportType,
|
|
|
+ transportType: row?.splitType || row?.transportType,
|
|
|
detail: {
|
|
|
- ...row.detail,
|
|
|
- pickTime: '2024-02-05 09:30',
|
|
|
- pickAddr: row.detail?.pickAddr || '北京市朝阳区某小区5号楼2单元101',
|
|
|
- pickContact: '李先生',
|
|
|
- pickPhone: '13812345678',
|
|
|
- dropTime: '2024-02-05 18:30',
|
|
|
- dropAddr: row.detail?.dropAddr || '北京市朝阳区某小区5号楼2单元101',
|
|
|
- dropContact: '李先生',
|
|
|
- dropPhone: '13812345678',
|
|
|
- packageName: row.detail?.packageName || '精细洗护套餐A',
|
|
|
- petStatus: '胆小,需安抚',
|
|
|
- area: '北京市朝阳区某小区5号楼2单元101'
|
|
|
+ ...row?.detail,
|
|
|
+ pickTime: row?.detail?.pickTime || '',
|
|
|
+ pickAddr: row?.detail?.pickAddr || '',
|
|
|
+ pickContact: row?.detail?.pickContact || '',
|
|
|
+ pickPhone: row?.detail?.pickPhone || '',
|
|
|
+ dropTime: row?.detail?.dropTime || '',
|
|
|
+ dropAddr: row?.detail?.dropAddr || '',
|
|
|
+ dropContact: row?.detail?.dropContact || '',
|
|
|
+ dropPhone: row?.detail?.dropPhone || '',
|
|
|
+ packageName: row?.detail?.packageName || '',
|
|
|
+ petStatus: row?.detail?.petStatus || '',
|
|
|
+ area: row?.detail?.area || ''
|
|
|
},
|
|
|
- petGender: 'male',
|
|
|
- petAge: '2岁',
|
|
|
- petWeight: '15kg',
|
|
|
- petVaccine: '已接种',
|
|
|
- petSterilized: true,
|
|
|
- petCharacter: '活泼好动,喜欢球类玩具',
|
|
|
- petHealth: '健康良好',
|
|
|
- fulfillerAvatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
|
|
|
- fulfillerPhone: '13812345678',
|
|
|
- fulfillerStation: '朝阳服务站',
|
|
|
- orderLogs: [
|
|
|
- { time: '2024-02-04 09:30', title: '订单创建', content: '商户提交订单', icon: 'Document' },
|
|
|
- { time: '2024-02-04 10:00', title: '系统派单', content: '指派给 王大力', icon: 'Bicycle' },
|
|
|
- { time: '2024-02-04 10:05', title: '接单成功', content: '履约者已确认接单', icon: 'CircleCheck' },
|
|
|
- { time: '2024-02-04 13:55', title: '到达服务点', content: '履约者已打卡', icon: 'Location' }
|
|
|
- ]
|
|
|
+ petGender: '',
|
|
|
+ petAge: '',
|
|
|
+ petWeight: '',
|
|
|
+ petVaccine: '',
|
|
|
+ petSterilized: undefined,
|
|
|
+ petCharacter: '',
|
|
|
+ petHealth: '',
|
|
|
+ fulfillerAvatar: '',
|
|
|
+ fulfillerPhone: '',
|
|
|
+ fulfillerStation: '',
|
|
|
+ orderLogs: []
|
|
|
};
|
|
|
|
|
|
try {
|
|
|
@@ -473,6 +468,7 @@ const handleDetail = async (row) => {
|
|
|
platformId: info.platformId ?? currentOrder.value?.platformId,
|
|
|
groupBuyPackage: info.groupPurchasePackageName || currentOrder.value?.groupBuyPackage,
|
|
|
fulfiller: info.fulfiller ?? currentOrder.value?.fulfiller,
|
|
|
+ remark: info.remark ?? currentOrder.value?.remark,
|
|
|
detail: {
|
|
|
...(currentOrder.value?.detail || {}),
|
|
|
pickTime: info.serviceTime || currentOrder.value?.detail?.pickTime,
|
|
|
@@ -493,7 +489,7 @@ const handleDetail = async (row) => {
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
- } catch {}
|
|
|
+ } catch { }
|
|
|
detailVisible.value = true;
|
|
|
};
|
|
|
|
|
|
@@ -505,12 +501,19 @@ const handlePetDetail = (row) => {
|
|
|
|
|
|
// 取消订单
|
|
|
const handleCancel = (row) => {
|
|
|
- ElMessageBox.confirm('确认取消该订单吗?', '提示', { type: 'warning' }).then(() => {
|
|
|
- cancelSubOrder({ orderId: row?.id }).then(() => {
|
|
|
+ ElMessageBox.prompt('请输入取消订单的原因', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ inputPattern: /\S+/,
|
|
|
+ inputErrorMessage: '取消原因不能为空',
|
|
|
+ inputPlaceholder: '必填,请输入取消原因',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(({ value }) => {
|
|
|
+ cancelSubOrder({ orderId: row?.id, reason: value }).then(() => {
|
|
|
ElMessage.success('订单已取消');
|
|
|
handleSearch();
|
|
|
});
|
|
|
- });
|
|
|
+ }).catch(() => { });
|
|
|
};
|
|
|
|
|
|
// 派单
|
|
|
@@ -565,7 +568,8 @@ const handleDispatchSubmit = (payload) => {
|
|
|
if (row) {
|
|
|
row.status = 1;
|
|
|
row.fulfillerName = payload.riderName || 'Unknown';
|
|
|
- row.price = payload.fee;
|
|
|
+ row.fulfillerPhone = payload.riderPhone;
|
|
|
+ row.price = Math.round(Number(payload.fee || 0) * 100);
|
|
|
}
|
|
|
handleSearch();
|
|
|
});
|