Bladeren bron

服务类型修改完成

Huanyi 2 weken geleden
bovenliggende
commit
f34374993d

+ 1 - 1
src/api/order/subOrder/index.ts

@@ -26,7 +26,7 @@ export const listSubOrder = (query?: SubOrderQuery): AxiosPromise<{ total: numbe
     });
 };
 
-export const dispatchSubOrder = (data: { orderId: string | number; fulfiller: string | number; price: number; }) => {
+export const dispatchSubOrder = (data: { orderId: string | number; fulfiller: string | number; fulfillmentCommission: number; }) => {
     return request({
         url: '/order/subOrder/dispatch',
         method: 'put',

+ 1 - 1
src/api/order/subOrder/types.ts

@@ -32,7 +32,7 @@ export interface SubOrderVO {
     fulfillerName: string;
     fulfillerGender?: string;
     fulfillerStatus?: 'resting' | 'busy' | 'disabled';
-    price: number;
+    fulfillmentCommission: number;
     // 以下为可能需要用到的扩充字段以兼顾页面展现
     type?: string;
     transportType?: string;

+ 10 - 0
src/api/service/list/types.ts

@@ -53,6 +53,11 @@ export interface ServiceVO {
    */
   classificationId: number;
 
+  /**
+   * 订单服务费(单位:分)
+   */
+  price: number;
+
   /**
    * 创建时间
    */
@@ -109,6 +114,11 @@ export interface ServiceForm extends BaseEntity {
    * 所属分类ID
    */
   classificationId?: number;
+
+  /**
+   * 订单服务费(单位:分)
+   */
+  price?: number;
 }
 
 export interface ServiceQuery extends PageQuery {

+ 2 - 2
src/views/login.vue

@@ -94,8 +94,8 @@ const { t } = useI18n();
 const loginForm = ref<LoginData>({
   platformId: 0,
   tenantId: '000000',
-  username: '',
-  password: '',
+  username: 'admin',
+  password: 'admin123',
   rememberMe: false,
   code: '',
   uuid: ''

+ 3 - 3
src/views/order/dispatch/components/DispatchDialog.vue

@@ -271,7 +271,7 @@ watch(() => props.visible, (val) => {
         dispatchSearchQuery.value = ''
         selectedRiderId.value = null
         // price 单位为分,转成元显示
-        dispatchFee.value = props.order?.price ? Number((props.order.price / 100).toFixed(2)) : 0
+        dispatchFee.value = props.order?.fulfillmentCommission ? Number((props.order.fulfillmentCommission / 100).toFixed(2)) : 0
         if (props.order?.riderId) {
             currentRider.value = {
                 id: props.order.riderId,
@@ -294,8 +294,8 @@ watch(() => props.visible, (val) => {
                 petId.value = res.data.usrPet?.id || res.data.usrPet
                 
                 // 接到详情后,把真实的金额放进去(后端金额单位为分)
-                if (res.data.price !== undefined && res.data.price !== null) {
-                    dispatchFee.value = Number((res.data.price / 100).toFixed(2))
+                if (res.data.fulfillmentCommission !== undefined && res.data.fulfillmentCommission !== null) {
+                    dispatchFee.value = Number((res.data.fulfillmentCommission / 100).toFixed(2))
                 }
 
                 // 如果已经有履约者且不是在列表中找到的,从详情中补全性别

+ 1 - 1
src/views/order/dispatch/index.vue

@@ -555,7 +555,7 @@ const handleDispatchSubmit = async (data) => {
     await dispatchSubOrder({
       orderId: currentDispatchOrder.value.id,
       fulfiller: data.riderId,
-      price: priceFen
+      fulfillmentCommission: priceFen
     });
     ElMessage.success('派单成功');
     dispatchDialogVisible.value = false;

+ 3 - 3
src/views/order/orderList/components/DispatchDialog.vue

@@ -273,7 +273,7 @@ watch(() => props.visible, (val) => {
         dispatchSearchQuery.value = ''
         selectedRiderId.value = null
         // price 单位为分,转成元显示
-        dispatchFee.value = props.order?.price ? Number((props.order.price / 100).toFixed(2)) : 0
+        dispatchFee.value = props.order?.fulfillmentCommission ? Number((props.order.fulfillmentCommission / 100).toFixed(2)) : 0
         if (props.order?.riderId) {
             currentRider.value = {
                 id: props.order.riderId,
@@ -297,8 +297,8 @@ watch(() => props.visible, (val) => {
                 petId.value = res.data.usrPet?.id || res.data.usrPet
                 
                 // 接到详情后,把真实的金额放进去(后端金额单位为分)
-                if (res.data.price !== undefined && res.data.price !== null) {
-                    dispatchFee.value = Number((res.data.price / 100).toFixed(2))
+                if (res.data.fulfillmentCommission !== undefined && res.data.fulfillmentCommission !== null) {
+                    dispatchFee.value = Number((res.data.fulfillmentCommission / 100).toFixed(2))
                 }
 
                 // 如果已经有履约者且不是在列表中找到的,从详情中补全性别

+ 5 - 5
src/views/order/orderList/index.vue

@@ -106,7 +106,7 @@
           <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 class="fulfiller-fee" v-if="row.fulfillmentCommission !== null && row.fulfillmentCommission !== undefined">¥{{ row.fulfillmentCommission / 100.0
               }}</span>
             </div>
             <span v-else class="text-gray">暂未指派</span>
@@ -468,8 +468,8 @@ const handleDetail = async (row) => {
           info.mode === 1 || info.mode === '1'
             ? info.toAddress || currentOrder.value?.address
             : info.address || info.toAddress || currentOrder.value?.address,
-        price: info.price !== undefined && info.price !== null ? Number(info.price) / 100 : currentOrder.value?.price,
-        fulfillerFee: info.price !== undefined && info.price !== null ? Number(info.price) / 100 : currentOrder.value?.fulfillerFee,
+        fulfillmentCommission: info.fulfillmentCommission !== undefined && info.fulfillmentCommission !== null ? Number(info.fulfillmentCommission) / 100 : currentOrder.value?.fulfillmentCommission,
+        fulfillerFee: info.fulfillmentCommission !== undefined && info.fulfillmentCommission !== null ? Number(info.fulfillmentCommission) / 100 : currentOrder.value?.fulfillerFee,
         merchantName: info.storeName || currentOrder.value?.merchantName,
         platformId: info.platformId ?? currentOrder.value?.platformId,
         groupBuyPackage: info.groupPurchasePackageName || currentOrder.value?.groupBuyPackage,
@@ -552,14 +552,14 @@ const handleDispatchSubmit = (payload) => {
   dispatchSubOrder({
     orderId: currentDispatchOrder.value.id,
     fulfiller: payload.riderId,
-    price: priceFen
+    fulfillmentCommission: priceFen
   }).then(() => {
     ElMessage.success('派单成功');
     const row = tableData.value.find((r) => r.id === currentDispatchOrder.value.id);
     if (row) {
       row.status = 1;
       row.fulfillerName = payload.riderName || 'Unknown';
-      row.price = payload.fee;
+      row.fulfillmentCommission = payload.fee;
     }
     handleSearch();
   });

+ 13 - 13
src/views/order/purchase/index.vue

@@ -223,11 +223,11 @@ const serviceList = [
 ]
 
 const allPackages = [
-  { id: 10, type: 'transport', name: '包月接送套餐', price: 0 },
-  { id: 11, type: 'feeding', name: '基础喂猫套餐', price: 0 },
-  { id: 12, type: 'feeding', name: '深度陪玩套餐', price: 0 },
-  { id: 13, type: 'washing', name: '精致洗护+美容', price: 0 },
-  { id: 14, type: 'washing', name: '除菌药浴套餐', price: 0 },
+  { id: 10, type: 'transport', name: '包月接送套餐', fulfillmentCommission: 0 },
+  { id: 11, type: 'feeding', name: '基础喂猫套餐', fulfillmentCommission: 0 },
+  { id: 12, type: 'feeding', name: '深度陪玩套餐', fulfillmentCommission: 0 },
+  { id: 13, type: 'washing', name: '精致洗护+美容', fulfillmentCommission: 0 },
+  { id: 14, type: 'washing', name: '除菌药浴套餐', fulfillmentCommission: 0 },
 ]
 
 const currentPets = ref([])
@@ -249,7 +249,7 @@ const form = reactive({
   // Sub Forms Data
   transport: {
     pkgId: '',
-    price: 0,
+    fulfillmentCommission: 0,
     pickPrice: 35,
     dropPrice: 35,
     subType: 'round',
@@ -257,13 +257,13 @@ const form = reactive({
     dropStartRegion: [], dropStartDetail: '', dropEndRegion: [], dropEndDetail: '', dropContact: '', dropPhone: '', dropTime: ''
   },
   feeding: {
-    pkgId: '', price: 68,
+    pkgId: '', fulfillmentCommission: 68,
     appointments: [{ startTime: '', endTime: '' }],
     region: [], addressDetail: '',
     count: 1, dates: [], area: '', itemLoc: '', cleanLoc: '', foodAmount: '', other: ''
   },
   washing: {
-    pkgId: '', price: 88,
+    pkgId: '', fulfillmentCommission: 88,
     appointments: [{ startTime: '', endTime: '' }],
     region: [], addressDetail: '',
     time: '', petStatus: '', cleanLoc: '', toolLoc: '', other: ''
@@ -403,9 +403,9 @@ const calcPrice = (type) => {
       data.dropPrice = base
     }
   } else if (type === 'feeding') {
-    data.price = base * data.count
+    data.fulfillmentCommission = base * data.count
   } else if (type === 'washing') {
-    data.price = base
+    data.fulfillmentCommission = base
   }
 }
 
@@ -565,7 +565,7 @@ const resetForm = () => {
 
   form.transport = {
     pkgId: '',
-    price: 0,
+    fulfillmentCommission: 0,
     pickPrice: 35,
     dropPrice: 35,
     subType: 'round',
@@ -573,13 +573,13 @@ const resetForm = () => {
     dropStartRegion: [], dropStartDetail: '', dropEndRegion: [], dropEndDetail: '', dropContact: '', dropPhone: '', dropTime: ''
   }
   form.feeding = {
-    pkgId: '', price: 68,
+    pkgId: '', fulfillmentCommission: 68,
     appointments: [{ startTime: '', endTime: '' }],
     region: [], addressDetail: '',
     count: 1, dates: [], area: '', itemLoc: '', cleanLoc: '', foodAmount: '', other: ''
   }
   form.washing = {
-    pkgId: '', price: 88,
+    pkgId: '', fulfillmentCommission: 88,
     appointments: [{ startTime: '', endTime: '' }],
     region: [], addressDetail: '',
     time: '', petStatus: '', cleanLoc: '', toolLoc: '', other: ''

+ 57 - 15
src/views/service/classification/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div class="gen-container">
-    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
+      :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div v-show="showSearch" class="search-wrapper">
         <el-card shadow="hover" class="search-card">
           <el-form ref="queryFormRef" :model="queryParams" :inline="true">
@@ -26,16 +27,17 @@
             <span class="header-title">服务分类列表</span>
           </div>
           <div class="header-right">
-            <el-button type="primary" size="small" @click="handleAdd" v-hasPermi="['service:classification:add']">新增</el-button>
-            <el-button type="success" size="small" :disabled="single" @click="handleUpdate()" v-hasPermi="['service:classification:edit']">修改</el-button>
-            <el-button type="danger" size="small" :disabled="multiple" @click="handleDelete()" v-hasPermi="['service:classification:remove']">删除</el-button>
-            <el-button type="warning" size="small" @click="handleExport" v-hasPermi="['service:classification:export']">导出</el-button>
+            <el-button type="primary" size="small" @click="handleAdd"
+              v-hasPermi="['service:classification:add']">新增</el-button>
+            <el-button type="danger" size="small" :disabled="multiple" @click="handleDelete()"
+              v-hasPermi="['service:classification:remove']">删除</el-button>
             <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
           </div>
         </div>
       </template>
 
-      <el-table v-loading="loading" stripe :data="classificationList" @selection-change="handleSelectionChange" class="gen-table">
+      <el-table v-loading="loading" stripe :data="classificationList" @selection-change="handleSelectionChange"
+        class="gen-table">
         <el-table-column type="selection" width="55" align="center" />
         <el-table-column label="序号" align="center" prop="id" v-if="false" />
         <el-table-column label="类型名称" align="center" prop="name" />
@@ -48,13 +50,16 @@
         </el-table-column>
         <el-table-column label="操作" align="center" width="160" fixed="right">
           <template #default="scope">
-            <el-button link type="primary" size="small" @click="handleUpdate(scope.row)" v-hasPermi="['service:classification:edit']">编辑</el-button>
-            <el-button link type="danger" size="small" @click="handleDelete(scope.row)" v-hasPermi="['service:classification:remove']">删除</el-button>
+            <el-button link type="primary" size="small" @click="handleUpdate(scope.row)"
+              v-hasPermi="['service:classification:edit']">编辑</el-button>
+            <el-button link type="danger" size="small" @click="handleDelete(scope.row)"
+              v-hasPermi="['service:classification:remove']">删除</el-button>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
     <!-- 添加或修改服务分类对话框 -->
     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@@ -66,7 +71,7 @@
           <el-input v-model="form.sort" placeholder="请输入排序" />
         </el-form-item>
         <el-form-item label="备注" prop="remark">
-            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -109,7 +114,7 @@ const initFormData: ClassificationForm = {
   remark: undefined,
 }
 const data = reactive<PageData<ClassificationForm, ClassificationQuery>>({
-  form: {...initFormData},
+  form: { ...initFormData },
   queryParams: {
     pageNum: 1,
     pageSize: 10,
@@ -150,7 +155,7 @@ const cancel = () => {
 
 /** 表单重置 */
 const reset = () => {
-  form.value = {...initFormData};
+  form.value = { ...initFormData };
   classificationFormRef.value?.resetFields();
 }
 
@@ -196,9 +201,9 @@ const submitForm = () => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.id) {
-        await updateClassification(form.value).finally(() =>  buttonLoading.value = false);
+        await updateClassification(form.value).finally(() => buttonLoading.value = false);
       } else {
-        await addClassification(form.value).finally(() =>  buttonLoading.value = false);
+        await addClassification(form.value).finally(() => buttonLoading.value = false);
       }
       proxy?.$modal.msgSuccess("操作成功");
       dialog.visible = false;
@@ -210,7 +215,44 @@ const submitForm = () => {
 /** 删除按钮操作 */
 const handleDelete = async (row?: ClassificationVO) => {
   const _ids = row?.id || ids.value;
-  await proxy?.$modal.confirm('是否确认删除服务分类编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  let confirmMsg = '';
+
+  if (row) {
+    confirmMsg = `
+      <div style="text-align: left;">
+        <p style="margin-bottom: 12px;">是否确认删除以下服务分类?</p>
+        <div style="padding: 8px 0; line-height: 1.8;">
+          <div>名称:${row.name || '-'}</div>
+          <div>排序:${row.sort ?? '-'}</div>
+          <div>备注:${row.remark || '-'}</div>
+        </div>
+      </div>
+    `;
+  } else {
+    const selectedItems = classificationList.value.filter(item => ids.value.includes(item.id));
+    if (selectedItems.length === 1) {
+      const item = selectedItems[0];
+      confirmMsg = `
+        <div style="text-align: left;">
+          <p style="margin-bottom: 12px;">是否确认删除以下服务分类?</p>
+          <div style="padding: 8px 0; line-height: 1.8;">
+            <div>名称:${item.name || '-'}</div>
+            <div>排序:${item.sort ?? '-'}</div>
+            <div>备注:${item.remark || '-'}</div>
+          </div>
+        </div>
+      `;
+    } else {
+      confirmMsg = `是否确认删除选中的 ${selectedItems.length} 条服务分类数据?`;
+    }
+  }
+
+  await ElMessageBox.confirm(confirmMsg, '系统提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning',
+    dangerouslyUseHTMLString: true
+  }).finally(() => loading.value = false);
   await delClassification(_ids);
   proxy?.$modal.msgSuccess("删除成功");
   await getList();

+ 30 - 18
src/views/service/list/index.vue

@@ -44,6 +44,11 @@
             </el-tag>
           </template>
         </el-table-column>
+        <el-table-column label="订单服务费" align="center" width="120">
+          <template #default="scope">
+            <span class="price-text">¥{{ formatPrice(scope.row.price) }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="备注说明" prop="remark" min-width="250" show-overflow-tooltip />
         <el-table-column label="创建时间" align="center" width="180">
           <template #default="scope">
@@ -92,6 +97,13 @@
         <el-form-item label="排序权重" prop="sort">
           <el-input-number v-model="form.sort" :min="0" controls-position="right" style="width: 100%" />
         </el-form-item>
+        <el-form-item label="订单服务费" prop="price">
+          <el-input-number v-model="form.price" :min="0" :precision="2" :step="0.01" controls-position="right"
+            style="width: 100%">
+            <template #prefix>¥</template>
+          </el-input-number>
+          <div style="color: #909399; font-size: 12px; margin-top: 4px;">单位:元</div>
+        </el-form-item>
         <el-form-item label="服务介绍" prop="introduction">
           <editor v-model="form.introduction" :min-height="300" />
         </el-form-item>
@@ -122,7 +134,7 @@
       <template #footer>
         <div class="dialog-footer">
           <el-button @click="cancel">取 消</el-button>
-          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm()">确 定</el-button>
         </div>
       </template>
     </el-dialog>
@@ -171,6 +183,7 @@ const initFormData: ServiceForm = {
   introduction: undefined,
   orderInstruction: undefined,
   classificationId: undefined,
+  price: undefined,
   tenantId: undefined
 };
 
@@ -245,6 +258,12 @@ const getClassificationName = (classificationId: number): string => {
   return classification ? classification.name : '-';
 };
 
+/** 格式化价格(分转元) */
+const formatPrice = (price: number): string => {
+  if (price === undefined || price === null) return '0.00';
+  return (price / 100).toFixed(2);
+};
+
 /** 取消按钮 */
 const cancel = () => {
   reset();
@@ -280,22 +299,11 @@ const handleUpdate = async (row: ServiceVO) => {
   const res = await getService(row.id);
   Object.assign(form.value, res.data);
 
-  // 解码富文本字段
-  if (form.value.introduction) {
-    try {
-      form.value.introduction = decodeURIComponent(atob(form.value.introduction));
-    } catch (e) {
-      console.error('服务介绍解码失败:', e);
-    }
-  }
-  if (form.value.orderInstruction) {
-    try {
-      form.value.orderInstruction = decodeURIComponent(atob(form.value.orderInstruction));
-    } catch (e) {
-      console.error('下单须知解码失败:', e);
-    }
+  if (form.value.price !== undefined && form.value.price !== null) {
+    form.value.price = form.value.price / 100;
   }
 
+
   if (form.value.clockInRemark) {
     try {
       const parsed = JSON.parse(form.value.clockInRemark);
@@ -318,13 +326,17 @@ const submitForm = () => {
     if (valid) {
       form.value.clockInRemark = clockInRemarkList.value.length > 0 ? JSON.stringify(clockInRemarkList.value) : undefined;
 
-      // 编码富文本字段
+      // 编码富文本字段为BASE64
       const submitData = { ...form.value };
       if (submitData.introduction) {
-        submitData.introduction = btoa(encodeURIComponent(submitData.introduction));
+        submitData.introduction = btoa(unescape(encodeURIComponent(submitData.introduction)));
       }
       if (submitData.orderInstruction) {
-        submitData.orderInstruction = btoa(encodeURIComponent(submitData.orderInstruction));
+        submitData.orderInstruction = btoa(unescape(encodeURIComponent(submitData.orderInstruction)));
+      }
+
+      if (submitData.price !== undefined && submitData.price !== null) {
+        submitData.price = Math.round(submitData.price * 100);
       }
 
       buttonLoading.value = true;