|
|
@@ -4,28 +4,11 @@
|
|
|
|
|
|
<!-- 左侧:下单填写区 -->
|
|
|
<div class="form-container">
|
|
|
- <!-- 1. 服务类型选择 -->
|
|
|
- <div class="type-selection">
|
|
|
- <div
|
|
|
- v-for="item in serviceList"
|
|
|
- :key="item.type"
|
|
|
- class="type-card"
|
|
|
- :class="[item.type, { active: form.type === item.type }]"
|
|
|
- @click="handleTypeChange(item.type)"
|
|
|
- >
|
|
|
- <div class="icon-box"><el-icon><component :is="item.icon" /></el-icon></div>
|
|
|
- <div class="text">
|
|
|
- <div class="type-name">{{ item.name }}</div>
|
|
|
- <div class="type-desc">{{ item.desc }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 2. 基础信息:门店与宠主 -->
|
|
|
+ <!-- 1. 基础信息:门店与宠主 -->
|
|
|
<el-card shadow="never" class="section-card">
|
|
|
<template #header>
|
|
|
<div class="card-title">
|
|
|
- <span class="step-num">02</span> 基础信息
|
|
|
+ <span class="step-num">01</span> 基础信息
|
|
|
</div>
|
|
|
</template>
|
|
|
<div class="card-body">
|
|
|
@@ -38,9 +21,17 @@
|
|
|
<span>服务门店 (平台代下单)</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
- <el-select v-model="form.merchantId" placeholder="请选择商户门店" size="large" style="width: 100%" filterable>
|
|
|
- <el-option v-for="m in merchants" :key="m.id" :label="m.name" :value="m.id" />
|
|
|
- </el-select>
|
|
|
+ <PageSelect
|
|
|
+ v-model="form.merchantId"
|
|
|
+ placeholder="请选择商户门店"
|
|
|
+ size="large"
|
|
|
+ style="width: 100%"
|
|
|
+ :options="merchantOptions"
|
|
|
+ :total="storeTotal"
|
|
|
+ :page-size="5"
|
|
|
+ @page-change="handleStorePageChange"
|
|
|
+ @update:modelValue="handleStoreChange"
|
|
|
+ />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
@@ -51,19 +42,15 @@
|
|
|
<el-button type="primary" plain size="small" @click="openAddUser" icon="Plus" style="margin-left: 15px;">添加用户</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
- <el-select
|
|
|
+ <PageSelect
|
|
|
v-model="form.userId"
|
|
|
- placeholder="搜索手机号/姓名"
|
|
|
+ placeholder="搜索姓名/手机号"
|
|
|
size="large"
|
|
|
style="width: 100%"
|
|
|
- filterable
|
|
|
- remote
|
|
|
- :remote-method="searchUser"
|
|
|
- :loading="userLoading"
|
|
|
- @change="handleUserChange"
|
|
|
- >
|
|
|
- <el-option v-for="u in userOptions" :key="u.id" :label="u.name + ' - ' + u.phone" :value="u.id" />
|
|
|
- </el-select>
|
|
|
+ :options="userSelectOptions"
|
|
|
+ :total="userSelectOptions.length"
|
|
|
+ @update:modelValue="handleUserChange"
|
|
|
+ />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
@@ -96,12 +83,33 @@
|
|
|
</div>
|
|
|
</el-card>
|
|
|
|
|
|
+ <!-- 2. 服务类型选择 -->
|
|
|
+ <div class="type-selection" v-if="form.merchantId">
|
|
|
+ <div
|
|
|
+ v-for="item in availableServices"
|
|
|
+ :key="item.id"
|
|
|
+ class="type-card"
|
|
|
+ :class="[getServiceType(item.name), { active: form.serviceId === item.id }]"
|
|
|
+ @click="handleServiceChange(item)"
|
|
|
+ >
|
|
|
+ <div class="icon-box"><el-icon><component :is="getServiceIcon(item.name)" /></el-icon></div>
|
|
|
+ <div class="text">
|
|
|
+ <div class="type-name">{{ item.name }}</div>
|
|
|
+ <div class="type-desc">{{ item.remark }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="availableServices.length === 0" style="grid-column: 1 / -1; color: #909399; text-align: center; padding: 20px;">该门店暂无可选服务</div>
|
|
|
+ </div>
|
|
|
+ <div v-else style="color: #909399; margin: 20px 0; padding: 20px; text-align: center; background: #fff; border-radius: 8px;">
|
|
|
+ 请先在上一步中选择服务门店
|
|
|
+ </div>
|
|
|
+
|
|
|
<!-- 3. 业务详情表单 -->
|
|
|
<el-card shadow="never" class="section-card form-card" v-if="form.type">
|
|
|
<template #header>
|
|
|
<div class="card-title">
|
|
|
- <span class="step-num">03</span>
|
|
|
- {{ getStepTitle(form.type) }}
|
|
|
+ <span class="step-num">02</span>
|
|
|
+ {{ getStepTitle(form.mode, form.type) }}
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -114,193 +122,13 @@
|
|
|
<div class="divider"></div>
|
|
|
|
|
|
<!-- A. 宠物接送表单 -->
|
|
|
- <div v-show="form.type === 'transport'" class="business-form">
|
|
|
- <el-form-item label="接送模式">
|
|
|
- <el-radio-group v-model="form.transport.subType" size="large" @change="calcPrice('transport')">
|
|
|
- <el-radio-button label="round">往返接送</el-radio-button>
|
|
|
- <el-radio-button label="pick">单程接 (到店)</el-radio-button>
|
|
|
- <el-radio-button label="drop">单程送 (回家)</el-radio-button>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <div class="route-box">
|
|
|
- <!-- 接宠段 -->
|
|
|
- <div class="route-segment" v-if="['round', 'pick'].includes(form.transport.subType)">
|
|
|
- <div class="seg-badge start">接</div>
|
|
|
- <div class="seg-content">
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="8">
|
|
|
- <el-cascader v-model="form.transport.pickRegion" :options="pcaOptions" placeholder="省/市/区" style="width: 100%" />
|
|
|
- </el-col>
|
|
|
- <el-col :span="16">
|
|
|
- <el-input v-model="form.transport.pickDetail" placeholder="详细地址 (街道/门牌号)" prefix-icon="Location" />
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="12"><el-input v-model="form.transport.pickContact" placeholder="联系人" /></el-col>
|
|
|
- <el-col :span="12"><el-input v-model="form.transport.pickPhone" placeholder="电话" /></el-col>
|
|
|
- </el-row>
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="24">
|
|
|
- <el-date-picker v-model="form.transport.pickTime" type="datetime" placeholder="选择接宠时间" style="width: 100%" />
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 门店中转标识 -->
|
|
|
- <div class="route-connector">
|
|
|
- <div class="line"></div>
|
|
|
- <div class="store-node"><el-icon><Shop /></el-icon> 服务门店</div>
|
|
|
- <div class="line"></div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 送回段 -->
|
|
|
- <div class="route-segment" v-if="['round', 'drop'].includes(form.transport.subType)">
|
|
|
- <div class="seg-badge end">送</div>
|
|
|
- <div class="seg-content">
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="8">
|
|
|
- <el-cascader v-model="form.transport.dropRegion" :options="pcaOptions" placeholder="省/市/区" style="width: 100%" />
|
|
|
- </el-col>
|
|
|
- <el-col :span="16">
|
|
|
- <el-input v-model="form.transport.dropDetail" placeholder="详细地址" prefix-icon="Location" />
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="12"><el-input v-model="form.transport.dropContact" placeholder="联系人" /></el-col>
|
|
|
- <el-col :span="12"><el-input v-model="form.transport.dropPhone" placeholder="电话" /></el-col>
|
|
|
- </el-row>
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="24">
|
|
|
- <el-date-picker v-model="form.transport.dropTime" type="datetime" placeholder="预计送回时间 (可选)" style="width: 100%" />
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <TransportForm v-show="form.type === 'transport'" :transport-data="form.transport" :pca-options="pcaOptions" @change="calcPrice" />
|
|
|
|
|
|
<!-- B. 上门喂遛表单 -->
|
|
|
- <div v-show="form.type === 'feeding'" class="business-form">
|
|
|
-
|
|
|
- <div style="margin-bottom: 20px;">
|
|
|
- <div class="section-label">上门服务地址</div>
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="8">
|
|
|
- <el-cascader v-model="form.feeding.region" :options="pcaOptions" placeholder="省/市/区" style="width: 100%" />
|
|
|
- </el-col>
|
|
|
- <el-col :span="16">
|
|
|
- <el-input v-model="form.feeding.addressDetail" placeholder="详细地址 (街道/门牌号)" prefix-icon="Location" />
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div style="margin-bottom: 20px;">
|
|
|
- <div class="section-label" style="display:flex; align-items:center; margin-bottom:10px;">
|
|
|
- 预约服务时间
|
|
|
- <el-tag type="info" size="small" style="margin-left:10px;">共 {{ form.feeding.appointments.length }} 次</el-tag>
|
|
|
- </div>
|
|
|
- <div v-for="(item, index) in form.feeding.appointments" :key="index" style="display:flex; align-items:center; margin-bottom:10px;">
|
|
|
- <span style="width:30px; color:#999; font-size:12px; font-weight:bold;">{{ index + 1 }}.</span>
|
|
|
- <el-date-picker
|
|
|
- v-model="item.startTime"
|
|
|
- type="datetime"
|
|
|
- placeholder="开始时间"
|
|
|
- style="width: 200px; margin-right: 5px;"
|
|
|
- format="YYYY-MM-DD HH:mm"
|
|
|
- />
|
|
|
- <span style="margin:0 5px; color:#999;">~</span>
|
|
|
- <el-date-picker
|
|
|
- v-model="item.endTime"
|
|
|
- type="datetime"
|
|
|
- placeholder="结束时间 (可选)"
|
|
|
- style="width: 200px; margin-right: 15px;"
|
|
|
- format="YYYY-MM-DD HH:mm"
|
|
|
- />
|
|
|
-
|
|
|
- <div style="display:flex; gap:8px; margin-left:5px;">
|
|
|
- <el-button v-if="index === form.feeding.appointments.length - 1" type="primary" circle size="small" icon="Plus" @click="addAppointment('feeding')" />
|
|
|
- <el-button v-if="form.feeding.appointments.length > 1" type="danger" circle size="small" icon="Minus" @click="removeAppointment('feeding', index)" plain />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="remark-section">
|
|
|
- <div class="section-label">家庭服务及宠物档案备注</div>
|
|
|
- <el-row :gutter="15">
|
|
|
- <el-col :span="12"><el-input v-model="form.feeding.area" placeholder="宠物活动区域" /></el-col>
|
|
|
- <el-col :span="12"><el-input v-model="form.feeding.itemLoc" placeholder="物品存放位置" /></el-col>
|
|
|
- <el-col :span="12" style="margin-top:10px"><el-input v-model="form.feeding.cleanLoc" placeholder="清洗位置" /></el-col>
|
|
|
- <el-col :span="12" style="margin-top:10px"><el-input v-model="form.feeding.foodAmount" placeholder="喂食量标准" /></el-col>
|
|
|
- <el-col :span="24" style="margin-top:10px"><el-input v-model="form.feeding.other" type="textarea" :rows="2" placeholder="其他注意事项" /></el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <FeedingForm v-show="form.type === 'feeding'" :feeding-data="form.feeding" :pca-options="pcaOptions" @change="calcPrice" />
|
|
|
|
|
|
<!-- C. 上门洗护表单 -->
|
|
|
- <div v-show="form.type === 'washing'" class="business-form">
|
|
|
-
|
|
|
- <div style="margin-bottom: 20px;">
|
|
|
- <div class="section-label">上门服务地址</div>
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="8">
|
|
|
- <el-cascader v-model="form.washing.region" :options="pcaOptions" placeholder="省/市/区" style="width: 100%" />
|
|
|
- </el-col>
|
|
|
- <el-col :span="16">
|
|
|
- <el-input v-model="form.washing.addressDetail" placeholder="详细地址 (街道/门牌号)" prefix-icon="Location" />
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div style="margin-bottom: 20px;">
|
|
|
- <div class="section-label" style="display:flex; align-items:center; margin-bottom:10px;">
|
|
|
- 预约服务时间
|
|
|
- <el-tag type="info" size="small" style="margin-left:10px;">共 {{ form.washing.appointments.length }} 次</el-tag>
|
|
|
- </div>
|
|
|
- <div v-for="(item, index) in form.washing.appointments" :key="index" style="display:flex; align-items:center; margin-bottom:10px;">
|
|
|
- <span style="width:30px; color:#999; font-size:12px; font-weight:bold;">{{ index + 1 }}.</span>
|
|
|
- <el-date-picker
|
|
|
- v-model="item.startTime"
|
|
|
- type="datetime"
|
|
|
- placeholder="开始时间"
|
|
|
- style="width: 200px; margin-right: 5px;"
|
|
|
- format="YYYY-MM-DD HH:mm"
|
|
|
- />
|
|
|
- <span style="margin:0 5px; color:#999;">~</span>
|
|
|
- <el-date-picker
|
|
|
- v-model="item.endTime"
|
|
|
- type="datetime"
|
|
|
- placeholder="结束时间 (可选)"
|
|
|
- style="width: 200px; margin-right: 15px;"
|
|
|
- format="YYYY-MM-DD HH:mm"
|
|
|
- />
|
|
|
-
|
|
|
- <div style="display:flex; gap:8px; margin-left:5px;">
|
|
|
- <el-button v-if="index === form.washing.appointments.length - 1" type="primary" circle size="small" icon="Plus" @click="addAppointment('washing')" />
|
|
|
- <el-button v-if="form.washing.appointments.length > 1" type="danger" circle size="small" icon="Minus" @click="removeAppointment('washing', index)" plain />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="remark-section">
|
|
|
- <div class="section-label">服务备注及宠物状态</div>
|
|
|
- <el-row :gutter="15">
|
|
|
- <el-col :span="8">
|
|
|
- <el-select v-model="form.washing.petStatus" placeholder="宠物应激状态" style="width:100%">
|
|
|
- <el-option label="性格温顺" value="calm" />
|
|
|
- <!-- ... options ... -->
|
|
|
- <el-option label="胆小怕人" value="shy" />
|
|
|
- <el-option label="容易应激" value="stress" />
|
|
|
- <el-option label="有攻击性" value="aggressive" />
|
|
|
- </el-select>
|
|
|
- </el-col>
|
|
|
- <el-col :span="8"><el-input v-model="form.washing.cleanLoc" placeholder="清洗位置" /></el-col>
|
|
|
- <el-col :span="8"><el-input v-model="form.washing.toolLoc" placeholder="工具/水源位置" /></el-col>
|
|
|
- <el-col :span="24" style="margin-top:10px"><el-input v-model="form.washing.other" type="textarea" :rows="2" placeholder="其他注意事项" /></el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <WashingForm v-show="form.type === 'washing'" :washing-data="form.washing" :pca-options="pcaOptions" @change="calcPrice" />
|
|
|
|
|
|
</div>
|
|
|
</el-card>
|
|
|
@@ -327,7 +155,7 @@
|
|
|
<div class="divider"></div>
|
|
|
|
|
|
<div class="service-preview" v-if="form.type">
|
|
|
- <div class="preview-title">{{ getTypeName(form.type) }}</div>
|
|
|
+ <div class="preview-title">{{ selectedServiceName }}</div>
|
|
|
|
|
|
<!-- 套餐显示 -->
|
|
|
<div class="preview-detail" v-if="selectedPkgName">
|
|
|
@@ -359,267 +187,8 @@
|
|
|
|
|
|
<!-- Dialogs -->
|
|
|
<!-- Add User Dialog -->
|
|
|
- <el-dialog v-model="userDialogVisible" title="新增用户" width="700px" destroy-on-close append-to-body class="add-user-dialog">
|
|
|
- <el-form :model="userForm" label-width="90px" class="user-form">
|
|
|
-
|
|
|
- <div style="display: flex; justify-content: center; align-items: center; gap: 20px; margin-bottom: 30px;">
|
|
|
- <el-upload action="#" :show-file-list="false" :auto-upload="false" :on-change="handleUserAvatarChange">
|
|
|
- <el-avatar :size="80" :src="userForm.avatar || 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'" style="cursor: pointer; border: 2px solid #e4e7ed;" />
|
|
|
- </el-upload>
|
|
|
- <el-button type="primary" link @click="">点击修改头像</el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-section-header">基本资料</div>
|
|
|
- <el-row :gutter="30">
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="录入来源">
|
|
|
- <el-select v-model="userForm.source" style="width: 100%" filterable allow-create default-first-option>
|
|
|
- <el-option label="平台录入" value="平台录入" />
|
|
|
- <el-option label="萌它宠物连锁录入" value="萌它宠物连锁录入" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="所属区域">
|
|
|
- <el-select v-model="userForm.area" style="width: 100%" filterable allow-create default-first-option placeholder="请选择或输入">
|
|
|
- <el-option label="朝阳区" value="朝阳区" />
|
|
|
- <el-option label="海淀区" value="海淀区" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="姓名" required><el-input v-model="userForm.name" placeholder="请输入姓名" /></el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="电话" required><el-input v-model="userForm.phone" placeholder="请输入电话" /></el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="性别">
|
|
|
- <el-radio-group v-model="userForm.gender">
|
|
|
- <el-radio label="男">男</el-radio>
|
|
|
- <el-radio label="女">女</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <div class="form-section-header">居住信息</div>
|
|
|
- <el-row :gutter="30">
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="所在地区">
|
|
|
- <el-cascader v-model="userForm.region" :options="pcaOptions" placeholder="请选择省/市/区" style="width: 100%" />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="详细住址"><el-input v-model="userForm.detailAddress" placeholder="请输入街道/门牌号" /></el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="房屋类型">
|
|
|
- <el-radio-group v-model="userForm.houseType">
|
|
|
- <el-radio label="stairs">楼梯</el-radio>
|
|
|
- <el-radio label="elevator">电梯</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="入门方式">
|
|
|
- <el-radio-group v-model="userForm.entryMethod">
|
|
|
- <el-radio label="password">密码开门</el-radio>
|
|
|
- <el-radio label="key">钥匙开门</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12" v-if="userForm.entryMethod === 'password'">
|
|
|
- <el-form-item label="开门密码">
|
|
|
- <el-input v-model="userForm.entryPassword" placeholder="请输入密码" />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12" v-if="userForm.entryMethod === 'key'">
|
|
|
- <el-form-item label="钥匙位置">
|
|
|
- <el-input v-model="userForm.keyLocation" placeholder="如:地毯下" />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <div class="form-section-header">其他</div>
|
|
|
- <el-row :gutter="30">
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="用户标签">
|
|
|
- <el-select v-model="userSelectedTagIds" multiple placeholder="选择标签" style="width: 100%">
|
|
|
- <el-option v-for="tag in allUserTags" :key="tag.id" :label="tag.name" :value="tag.id">
|
|
|
- <el-tag :type="tag.type" effect="light" size="small">{{ tag.name }}</el-tag>
|
|
|
- </el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="备注说明"><el-input type="textarea" v-model="userForm.remark" rows="3" /></el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-form>
|
|
|
- <template #footer>
|
|
|
- <div style="text-align: center; margin-top: 20px;">
|
|
|
- <el-button @click="userDialogVisible = false" size="large" style="width: 120px;">取消</el-button>
|
|
|
- <el-button type="primary" @click="submitUser" size="large" style="width: 120px;">保存</el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
- <el-dialog v-model="petDialogVisible" title="宠物档案详情" width="800px" top="10vh" class="pet-profile-dialog">
|
|
|
- <el-tabs v-model="activePetTab" class="pet-tabs">
|
|
|
- <el-tab-pane label="基本信息" name="basic">
|
|
|
- <div class="pet-form-content">
|
|
|
- <!-- Avatar Upload -->
|
|
|
- <div class="avatar-col">
|
|
|
- <el-upload
|
|
|
- class="avatar-uploader"
|
|
|
- action="#"
|
|
|
- :show-file-list="false"
|
|
|
- :auto-upload="false"
|
|
|
- :on-change="handleAvatarChange"
|
|
|
- >
|
|
|
- <img v-if="petForm.avatar" :src="petForm.avatar" class="avatar" />
|
|
|
- <el-icon v-else class="avatar-uploader-icon" :size="28" color="#8c939d"><Plus /></el-icon>
|
|
|
- </el-upload>
|
|
|
- <div style="font-size:12px; color:#999; margin-top:8px; text-align:center">点击上传头像</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- Form Fields -->
|
|
|
- <el-form :model="petForm" label-width="80px" class="inner-form">
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="宠物姓名" required>
|
|
|
- <el-input v-model="petForm.name" placeholder="请输入" />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="所属主人" required>
|
|
|
- <el-select v-model="form.userId" disabled placeholder="选择主人" style="width:100%">
|
|
|
- <el-option v-for="u in userOptions" :key="u.id" :label="u.name" :value="u.id" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="性别">
|
|
|
- <el-radio-group v-model="petForm.gender">
|
|
|
- <el-radio label="MM">公</el-radio>
|
|
|
- <el-radio label="GG">母</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="品种">
|
|
|
- <el-select v-model="petForm.breed" placeholder="请选择品种" style="width:100%">
|
|
|
- <el-option label="金毛" value="金毛" />
|
|
|
- <el-option label="布偶" value="布偶" />
|
|
|
- <el-option label="边牧" value="边牧" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="体型">
|
|
|
- <el-select v-model="petForm.bodyType" placeholder="选择体型" style="width:100%">
|
|
|
- <el-option label="小型" value="small" />
|
|
|
- <el-option label="中型" value="medium" />
|
|
|
- <el-option label="大型" value="large" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="体重(kg)">
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="12"><el-input-number v-model="petForm.weight" :min="0" :step="0.1" controls="false" style="width:100%" /></el-col>
|
|
|
- <el-col :span="12"></el-col>
|
|
|
- </el-row>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="年龄(岁)">
|
|
|
- <el-input-number v-model="petForm.age" :min="0" style="width:100%" />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-form-item label="性格关键词">
|
|
|
- <el-input v-model="petForm.keywords" placeholder="如:活泼、粘人" />
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="萌宠性格">
|
|
|
- <el-input v-model="petForm.desc" type="textarea" placeholder="详细描述" :rows="2" />
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="宠物标签">
|
|
|
- <el-select v-model="petForm.tags" multiple placeholder="选择标签" style="width:100%">
|
|
|
- <el-option label="绝育" value="1" />
|
|
|
- <el-option label="疫苗齐全" value="2" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- </el-form>
|
|
|
- </div>
|
|
|
- </el-tab-pane>
|
|
|
- <el-tab-pane label="家庭信息" name="family">
|
|
|
- <el-form :model="petForm" label-width="120px">
|
|
|
- <el-form-item label="新来家庭时间">
|
|
|
- <el-date-picker v-model="petForm.arrivalTime" type="date" placeholder="选择日期" style="width: 100%" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="家庭房屋类型">
|
|
|
- <el-radio-group v-model="petForm.houseType">
|
|
|
- <el-radio label="stairs">楼梯</el-radio>
|
|
|
- <el-radio label="elevator">电梯</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="入门方式">
|
|
|
- <el-radio-group v-model="petForm.entryMethod">
|
|
|
- <el-radio label="password">密码开门</el-radio>
|
|
|
- <el-radio label="key">钥匙开门</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="密码" v-if="petForm.entryMethod === 'password'">
|
|
|
- <el-input v-model="petForm.entryPassword" placeholder="请输入门锁密码" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="钥匙位置" v-if="petForm.entryMethod === 'key'">
|
|
|
- <el-input v-model="petForm.keyLocation" placeholder="请输入钥匙存放位置" />
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- </el-tab-pane>
|
|
|
- <el-tab-pane label="健康状况" name="health">
|
|
|
- <el-form :model="petForm" label-width="120px">
|
|
|
- <el-form-item label="健康状态">
|
|
|
- <el-radio-group v-model="petForm.healthStatus">
|
|
|
- <el-radio label="健康">健康</el-radio>
|
|
|
- <el-radio label="亚健康">亚健康</el-radio>
|
|
|
- <el-radio label="疾病">疾病</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="是否有攻击倾向">
|
|
|
- <el-switch v-model="petForm.aggression" active-text="是" inactive-text="否" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="疫苗情况">
|
|
|
- <el-input v-model="petForm.vaccine" type="textarea" placeholder="记录疫苗接种情况" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="既往病史">
|
|
|
- <el-input v-model="petForm.medicalHistory" type="textarea" placeholder="如有病史请记录" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="过敏史">
|
|
|
- <el-input v-model="petForm.allergies" type="textarea" placeholder="如有过敏源请记录" />
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- </el-tab-pane>
|
|
|
- </el-tabs>
|
|
|
- <template #footer>
|
|
|
- <el-button @click="petDialogVisible = false">取消</el-button>
|
|
|
- <el-button type="primary" @click="submitPet">保存</el-button>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
+ <AddUserDialog v-model:visible="userDialogVisible" :pca-options="pcaOptions" @success="handleUserSuccess" />
|
|
|
+ <AddPetDialog v-model:visible="petDialogVisible" :user-id="form.userId" :user-options="userOptions" @success="handlePetSuccess" />
|
|
|
|
|
|
</div>
|
|
|
</template>
|
|
|
@@ -627,12 +196,17 @@
|
|
|
<script setup>
|
|
|
import { ref, reactive, computed, onMounted, watch } from 'vue'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
+import TransportForm from './components/TransportForm.vue'
|
|
|
+import FeedingForm from './components/FeedingForm.vue'
|
|
|
+import WashingForm from './components/WashingForm.vue'
|
|
|
+import AddUserDialog from './components/AddUserDialog.vue'
|
|
|
+import AddPetDialog from './components/AddPetDialog.vue'
|
|
|
+import PageSelect from '@/components/PageSelect/index.vue'
|
|
|
+import { listStoreOnOrder } from '@/api/system/store'
|
|
|
+import { listServiceOnOrder } from '@/api/service/list'
|
|
|
+import { regionData as pcaOptions } from 'element-china-area-data'
|
|
|
|
|
|
// --- Mock Data ---
|
|
|
-const merchants = ref([
|
|
|
- { id: 1, name: '萌它宠物三里屯店' },
|
|
|
- { id: 2, name: '宠爱国际动物医院' }
|
|
|
-])
|
|
|
const userOptions = ref([
|
|
|
{ id: 101, name: '张三', phone: '13812345678' },
|
|
|
{ id: 102, name: '李四', phone: '13987654321' }
|
|
|
@@ -665,11 +239,18 @@ const allPackages = [
|
|
|
const userLoading = ref(false)
|
|
|
const currentPets = ref([])
|
|
|
|
|
|
+const stores = ref([])
|
|
|
+const storeTotal = ref(0)
|
|
|
+const allServices = ref([])
|
|
|
+const storeQuery = reactive({ pageNum: 1, pageSize: 5 })
|
|
|
+
|
|
|
const form = reactive({
|
|
|
merchantId: '',
|
|
|
userId: '',
|
|
|
petId: '',
|
|
|
- type: 'transport',
|
|
|
+ serviceId: '',
|
|
|
+ type: '',
|
|
|
+ mode: undefined,
|
|
|
groupBuyPackage: '',
|
|
|
|
|
|
// Sub Forms Data
|
|
|
@@ -679,8 +260,8 @@ const form = reactive({
|
|
|
pickPrice: 35,
|
|
|
dropPrice: 35,
|
|
|
subType: 'round',
|
|
|
- pickRegion: [], pickDetail: '', pickContact: '', pickPhone: '', pickTime: '',
|
|
|
- dropRegion: [], dropDetail: '', dropContact: '', dropPhone: '', dropTime: ''
|
|
|
+ pickStartRegion: [], pickStartDetail: '', pickEndRegion: [], pickEndDetail: '', pickContact: '', pickPhone: '', pickTime: '',
|
|
|
+ dropStartRegion: [], dropStartDetail: '', dropEndRegion: [], dropEndDetail: '', dropContact: '', dropPhone: '', dropTime: ''
|
|
|
},
|
|
|
feeding: {
|
|
|
pkgId: '', price: 68,
|
|
|
@@ -705,13 +286,13 @@ watch(() => form.petId, (newId) => {
|
|
|
const user = userOptions.value.find(u => u.id === form.userId)
|
|
|
|
|
|
// Fill Transport
|
|
|
- form.transport.pickRegion = pet.region || []
|
|
|
- form.transport.pickDetail = pet.address || ''
|
|
|
+ form.transport.pickStartRegion = pet.region || []
|
|
|
+ form.transport.pickStartDetail = pet.address || ''
|
|
|
form.transport.pickContact = user?.name || ''
|
|
|
form.transport.pickPhone = user?.phone || ''
|
|
|
|
|
|
- form.transport.dropRegion = pet.region || []
|
|
|
- form.transport.dropDetail = pet.address || ''
|
|
|
+ form.transport.dropEndRegion = pet.region || []
|
|
|
+ form.transport.dropEndDetail = pet.address || ''
|
|
|
form.transport.dropContact = user?.name || ''
|
|
|
form.transport.dropPhone = user?.phone || ''
|
|
|
|
|
|
@@ -730,10 +311,53 @@ const activeData = computed(() => {
|
|
|
})
|
|
|
|
|
|
// --- Logic ---
|
|
|
+const fetchStores = () => {
|
|
|
+ listStoreOnOrder(storeQuery).then(res => {
|
|
|
+ stores.value = res.rows || []
|
|
|
+ storeTotal.value = res.total || 0
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const handleStorePageChange = (page) => {
|
|
|
+ storeQuery.pageNum = page
|
|
|
+ fetchStores()
|
|
|
+}
|
|
|
+
|
|
|
+const handleStoreChange = (val) => {
|
|
|
+ const store = stores.value.find(s => s.id === val)
|
|
|
+ if (store && store.services) {
|
|
|
+ if(!store.services.includes(form.serviceId)) {
|
|
|
+ form.serviceId = ''
|
|
|
+ form.type = ''
|
|
|
+ form.mode = undefined
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ form.serviceId = ''
|
|
|
+ form.type = ''
|
|
|
+ form.mode = undefined
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-const handleTypeChange = (type) => {
|
|
|
- form.type = type
|
|
|
- calcPrice(type)
|
|
|
+const getServiceType = (name) => {
|
|
|
+ if (!name) return 'transport'
|
|
|
+ if (name.includes('接送')) return 'transport'
|
|
|
+ if (name.includes('喂') || name.includes('遛')) return 'feeding'
|
|
|
+ if (name.includes('洗护') || name.includes('美容')) return 'washing'
|
|
|
+ return 'transport'
|
|
|
+}
|
|
|
+
|
|
|
+const getServiceIcon = (name) => {
|
|
|
+ const type = getServiceType(name)
|
|
|
+ const map = { transport: 'Van', feeding: 'Food', washing: 'Soap' }
|
|
|
+ return map[type] || 'Menu'
|
|
|
+}
|
|
|
+
|
|
|
+const handleServiceChange = (item) => {
|
|
|
+ form.serviceId = item.id
|
|
|
+ form.mode = item.mode
|
|
|
+ const sysType = getServiceType(item.name)
|
|
|
+ form.type = sysType
|
|
|
+ calcPrice(sysType)
|
|
|
}
|
|
|
|
|
|
const currentPackages = computed(() => {
|
|
|
@@ -769,155 +393,60 @@ const calcPrice = (type) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// Appointment Logic
|
|
|
-const addAppointment = (type) => {
|
|
|
- form[type].appointments.push({ startTime: '', endTime: '' })
|
|
|
- if(type === 'feeding') {
|
|
|
- form.feeding.count = form.feeding.appointments.length
|
|
|
- calcPrice('feeding')
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const removeAppointment = (type, index) => {
|
|
|
- if (form[type].appointments.length <= 1) return
|
|
|
- form[type].appointments.splice(index, 1)
|
|
|
- if(type === 'feeding') {
|
|
|
- form.feeding.count = form.feeding.appointments.length
|
|
|
- calcPrice('feeding')
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
// Add User Logic
|
|
|
const userDialogVisible = ref(false)
|
|
|
-const userSelectedTagIds = ref([])
|
|
|
-
|
|
|
-const allUserTags = [
|
|
|
- { id: 1, name: '优质客户', type: 'success' },
|
|
|
- { id: 2, name: '潜在流失', type: 'warning' },
|
|
|
- { id: 3, name: '黑名单', type: 'danger' }
|
|
|
-]
|
|
|
-
|
|
|
-const pcaOptions = [
|
|
|
- {
|
|
|
- value: '北京市', label: '北京市',
|
|
|
- children: [
|
|
|
- { value: '市辖区', label: '市辖区', children: [ { value: '朝阳区', label: '朝阳区' }, { value: '海淀区', label: '海淀区' } ] }
|
|
|
- ]
|
|
|
- },
|
|
|
- {
|
|
|
- value: '上海市', label: '上海市',
|
|
|
- children: [
|
|
|
- { value: '市辖区', label: '市辖区', children: [ { value: '浦东新区', label: '浦东新区' }, { value: '徐汇区', label: '徐汇区' } ] }
|
|
|
- ]
|
|
|
- }
|
|
|
-]
|
|
|
-
|
|
|
-const userForm = reactive({
|
|
|
- id: null, avatar: '', name: '', phone: '', gender: '男', address: '', detailAddress: '', region: [], remark: '',
|
|
|
- houseType: 'elevator', entryMethod: 'password', entryPassword: '', keyLocation: '',
|
|
|
- source: '平台录入', area: ''
|
|
|
-})
|
|
|
-
|
|
|
-const openAddUser = () => {
|
|
|
- userSelectedTagIds.value = []
|
|
|
- Object.assign(userForm, {
|
|
|
- id: null, avatar: '', name: '', phone: '', gender: '男', address: '', detailAddress: '', region: [], remark: '',
|
|
|
- houseType: 'elevator', entryMethod: 'password', entryPassword: '', keyLocation: '',
|
|
|
- source: '平台录入', area: ''
|
|
|
- })
|
|
|
- userDialogVisible.value = true
|
|
|
-}
|
|
|
-
|
|
|
-const handleUserAvatarChange = (uploadFile) => {
|
|
|
- userForm.avatar = URL.createObjectURL(uploadFile.raw)
|
|
|
-}
|
|
|
-
|
|
|
-const submitUser = () => {
|
|
|
- if(!userForm.name || !userForm.phone) {
|
|
|
- ElMessage.warning('请补全用户必填信息')
|
|
|
- return
|
|
|
- }
|
|
|
- const newUser = {
|
|
|
- id: Date.now(),
|
|
|
- name: userForm.name,
|
|
|
- phone: userForm.phone
|
|
|
- }
|
|
|
+const openAddUser = () => { userDialogVisible.value = true }
|
|
|
+const handleUserSuccess = (newUser) => {
|
|
|
userOptions.value.push(newUser)
|
|
|
form.userId = newUser.id
|
|
|
-
|
|
|
- // Clear pets for new user
|
|
|
currentPets.value = []
|
|
|
form.petId = ''
|
|
|
-
|
|
|
- userDialogVisible.value = false
|
|
|
ElMessage.success('用户添加成功并已选中')
|
|
|
}
|
|
|
|
|
|
+// Removed mocked pcaOptions since we now use element-china-area-data
|
|
|
+
|
|
|
// Add Pet Logic
|
|
|
const petDialogVisible = ref(false)
|
|
|
-const activePetTab = ref('basic')
|
|
|
-
|
|
|
-const petForm = reactive({
|
|
|
- name: '', breed: '', gender: 'MM', avatar: '',
|
|
|
- bodyType: 'small', weight: 0, age: 0, keywords: '', desc: '', tags: [],
|
|
|
-
|
|
|
- // Family
|
|
|
- arrivalTime: '', houseType: 'stairs', entryMethod: 'key', entryPassword: '', keyLocation: '',
|
|
|
- // Health
|
|
|
- healthStatus: '健康', aggression: false, vaccine: '', medicalHistory: '', allergies: ''
|
|
|
-})
|
|
|
-
|
|
|
-const openAddPet = () => {
|
|
|
- activePetTab.value = 'basic'
|
|
|
- Object.assign(petForm, {
|
|
|
- name: '', breed: '', gender: 'MM', avatar: '',
|
|
|
- bodyType: 'small', weight: 0, age: 0, keywords: '', desc: '', tags: [],
|
|
|
- arrivalTime: '', houseType: 'stairs', entryMethod: 'key', entryPassword: '', keyLocation: '',
|
|
|
- healthStatus: '健康', aggression: false, vaccine: '', medicalHistory: '', allergies: ''
|
|
|
- })
|
|
|
- petDialogVisible.value = true
|
|
|
-}
|
|
|
-
|
|
|
-const handleAvatarChange = (uploadFile) => {
|
|
|
- // Mock upload: create local URL
|
|
|
- petForm.avatar = URL.createObjectURL(uploadFile.raw)
|
|
|
-}
|
|
|
-
|
|
|
-const submitPet = () => {
|
|
|
- if(!petForm.name || !petForm.breed) {
|
|
|
- ElMessage.warning('请补全宠物必填信息')
|
|
|
- return
|
|
|
- }
|
|
|
- const newPet = {
|
|
|
- id: Date.now(),
|
|
|
- name: petForm.name,
|
|
|
- breed: petForm.breed,
|
|
|
- avatar: petForm.avatar
|
|
|
- }
|
|
|
+const openAddPet = () => { petDialogVisible.value = true }
|
|
|
+const handlePetSuccess = (newPet) => {
|
|
|
if(!currentPets.value) currentPets.value = []
|
|
|
currentPets.value.push(newPet)
|
|
|
form.petId = newPet.id
|
|
|
- petDialogVisible.value = false
|
|
|
ElMessage.success('宠物添加成功')
|
|
|
}
|
|
|
|
|
|
|
|
|
// --- Computed Helpers ---
|
|
|
-const selectedMerchantName = computed(() => merchants.value.find(m => m.id === form.merchantId)?.name)
|
|
|
+const merchantOptions = computed(() => {
|
|
|
+ return stores.value.map(m => ({ label: m.name, value: m.id }))
|
|
|
+})
|
|
|
+const availableServices = computed(() => {
|
|
|
+ const store = stores.value.find(s => s.id === form.merchantId)
|
|
|
+ if (!store || !store.services) return []
|
|
|
+ return allServices.value.filter(srv => store.services.includes(srv.id))
|
|
|
+})
|
|
|
+const userSelectOptions = computed(() => {
|
|
|
+ return userOptions.value.map(u => ({ label: `${u.name} - ${u.phone}`, value: u.id }))
|
|
|
+})
|
|
|
+const selectedMerchantName = computed(() => stores.value.find(m => m.id === form.merchantId)?.name)
|
|
|
const selectedUserName = computed(() => userOptions.value.find(u => u.id === form.userId)?.name)
|
|
|
const selectedPet = computed(() => currentPets.value.find(p => p.id === form.petId))
|
|
|
const selectedPetName = computed(() => selectedPet.value?.name)
|
|
|
const selectedPetBreed = computed(() => selectedPet.value?.breed)
|
|
|
+const selectedServiceName = computed(() => {
|
|
|
+ return availableServices.value.find(s => s.id === form.serviceId)?.name || getTypeName(form.type)
|
|
|
+})
|
|
|
|
|
|
const selectedPkgName = computed(() => {
|
|
|
- const pkgId = activeData.value.pkgId
|
|
|
+ const pkgId = activeData.value?.pkgId
|
|
|
return allPackages.find(p => p.id === pkgId)?.name || ''
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const canSubmit = computed(() => {
|
|
|
- if(!form.merchantId || !form.userId || !form.petId) return false
|
|
|
+ if(!form.merchantId || !form.userId || !form.petId || !form.serviceId) return false
|
|
|
return true
|
|
|
})
|
|
|
|
|
|
@@ -927,9 +456,12 @@ const handleUserChange = (val) => {
|
|
|
currentPets.value = mockPets[val] || []
|
|
|
form.petId = ''
|
|
|
}
|
|
|
-const getStepTitle = (type) => {
|
|
|
+const getStepTitle = (mode, type) => {
|
|
|
+ if (mode === 1 || mode === '1') return '填写接送路线与时间'
|
|
|
+ if (mode === 0 || mode === '0') return '选择套餐与服务的细则'
|
|
|
+ // 兼容兜底方案(当后端数据未返回 mode 时)
|
|
|
const map = { transport: '填写接送路线与时间', feeding: '选择套餐与服务的细则', washing: '选择套餐与服务的细则' }
|
|
|
- return map[type]
|
|
|
+ return map[type] || ''
|
|
|
}
|
|
|
const getTypeName = (type) => {
|
|
|
const map = { transport: '宠物接送', feeding: '上门喂遛', washing: '上门洗护' }
|
|
|
@@ -947,7 +479,10 @@ const handleSubmit = () => {
|
|
|
|
|
|
// Initialize
|
|
|
onMounted(() => {
|
|
|
- calcPrice('transport')
|
|
|
+ fetchStores()
|
|
|
+ listServiceOnOrder().then(res => {
|
|
|
+ allServices.value = res.data || []
|
|
|
+ })
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
@@ -1033,44 +568,6 @@ onMounted(() => {
|
|
|
transform: translateY(-2px);
|
|
|
}
|
|
|
|
|
|
-/* Dialog Styles */
|
|
|
-.pet-form-content { display: flex; gap: 20px; }
|
|
|
-.avatar-col { width: 120px; display: flex; flex-direction: column; align-items: center; padding-top: 10px; }
|
|
|
-.avatar-uploader {
|
|
|
- display: inline-block;
|
|
|
-}
|
|
|
-.avatar-uploader .el-upload {
|
|
|
- border: 1px dashed #d9d9d9;
|
|
|
- border-radius: 6px;
|
|
|
- cursor: pointer;
|
|
|
- position: relative;
|
|
|
- overflow: hidden;
|
|
|
- transition: var(--el-transition-duration-fast);
|
|
|
-}
|
|
|
-.avatar-uploader .el-upload:hover {
|
|
|
- border-color: var(--el-color-primary);
|
|
|
-}
|
|
|
-.avatar-uploader-icon {
|
|
|
- font-size: 28px;
|
|
|
- color: #8c939d;
|
|
|
- width: 100px;
|
|
|
- height: 100px;
|
|
|
- text-align: center;
|
|
|
- border: 1px dashed #d9d9d9;
|
|
|
- border-radius: 50%;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
-}
|
|
|
-.avatar {
|
|
|
- width: 100px;
|
|
|
- height: 100px;
|
|
|
- display: block;
|
|
|
- border-radius: 50%;
|
|
|
- object-fit: cover;
|
|
|
-}
|
|
|
-.inner-form { flex: 1; }
|
|
|
-
|
|
|
/* Type Selection */
|
|
|
.type-selection { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; }
|
|
|
.type-card {
|
|
|
@@ -1109,25 +606,7 @@ onMounted(() => {
|
|
|
.pkg-select-card .pkg-name { font-weight: bold; font-size: 14px; color: #303133; }
|
|
|
.pkg-select-card .pkg-desc { font-size: 12px; color: #909399; margin-top: 2px; }
|
|
|
|
|
|
-/* Business Form */
|
|
|
-.business-form { padding-top: 5px; }
|
|
|
-.route-box { background: #f9f9f9; padding: 20px; border-radius: 8px; border: 1px solid #EBEEF5; }
|
|
|
-.route-segment { display: flex; gap: 15px; }
|
|
|
-.seg-badge {
|
|
|
- width: 32px; height: 32px; background: #409eff; color: white; border-radius: 8px;
|
|
|
- text-align: center; line-height: 32px; font-weight: bold; flex-shrink: 0;
|
|
|
-}
|
|
|
-.seg-badge.end { background: #67c23a; }
|
|
|
-.seg-content { flex: 1; display: flex; flex-direction: column; gap: 10px; }
|
|
|
-
|
|
|
-.route-connector { display: flex; align-items: center; justify-content: center; margin: 15px 0; gap: 10px; color: #909399; font-size: 12px; }
|
|
|
-.route-connector .line { height: 1px; width: 80px; background: #dcdfe6; }
|
|
|
-.route-connector .store-node { background: white; padding: 4px 12px; border-radius: 20px; border: 1px solid #dcdfe6; display: flex; align-items: center; gap: 5px; }
|
|
|
-
|
|
|
.divider { height: 1px; background: #EBEEF5; margin: 15px 0; }
|
|
|
-.remark-section { background: #fdfdfd; border: 1px dashed #dcdfe6; padding: 15px; border-radius: 6px; margin-top: 20px; }
|
|
|
-.section-label { font-size: 13px; font-weight: bold; color: #606266; margin-bottom: 12px; }
|
|
|
-.tip { font-size: 12px; color: #e6a23c; margin-top: 4px; }
|
|
|
|
|
|
/* Sidebar */
|
|
|
.summary-sidebar { width: 320px; flex-shrink: 0; }
|