git init
This commit is contained in:
@@ -0,0 +1,553 @@
|
||||
{extend name="PatientAPP/layout" /}
|
||||
|
||||
{block name="css"}
|
||||
<link rel="stylesheet" href="/PatientAPP/Order/create.css" />
|
||||
{/block}
|
||||
|
||||
{block name="app"}
|
||||
<div id="app" v-cloak>
|
||||
<!-- 头部区域 -->
|
||||
<div class="header-section">
|
||||
<div class="header-top">
|
||||
<div class="header-left">
|
||||
<van-icon name="arrow-left" size="20" @click="goBack" />
|
||||
<span class="page-title">发布订单</span>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<div class="icon-btn" @click="onDraft">
|
||||
<van-icon name="description" size="17" />
|
||||
<span style="font-size:11px;margin-left:3px;">草稿</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表单主体 -->
|
||||
<div class="form-wrapper">
|
||||
<!-- 服务类型选择 -->
|
||||
<div class="form-card form-card-type">
|
||||
<div class="fc-label"><van-icon name="apps-o" color="#018fa5" size="16" /> 选择服务类型</div>
|
||||
<div class="type-grid">
|
||||
<div class="type-item"
|
||||
:class="{ 'type-active': form.serviceType === item.value }"
|
||||
v-for="(item, index) in serviceTypes"
|
||||
:key="index"
|
||||
@click="selectServiceType(item.value)">
|
||||
<div class="type-icon-wrap" :class="'wrap-' + item.value">
|
||||
<van-icon :name="item.icon" size="24" :color="form.serviceType === item.value ? '#fff' : item.color" />
|
||||
</div>
|
||||
<span class="type-name">{{ item.label }}</span>
|
||||
<span class="type-desc">{{ item.desc }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 患者信息 -->
|
||||
<div class="form-card">
|
||||
<div class="fc-header">
|
||||
<div class="fc-label"><van-icon name="contact" color="#018fa5" size="16" /> 患者信息</div>
|
||||
</div>
|
||||
<div class="fc-body">
|
||||
<van-field v-model="form.patientName" label="姓名" placeholder="请输入患者姓名" clearable />
|
||||
<van-field v-model="form.patientPhone" label="联系电话" type="tel" placeholder="请输入联系电话" clearable />
|
||||
<van-field v-model="form.patientAge" label="年龄" type="digit" placeholder="请输入年龄" />
|
||||
<van-field v-model="form.patientGender" label="性别" readonly placeholder="请选择" is-link @click="showGenderPicker = true" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 服务时间 -->
|
||||
<div class="form-card">
|
||||
<div class="fc-header">
|
||||
<div class="fc-label"><van-icon name="clock-o" color="#018fa5" size="16" /> 服务时间</div>
|
||||
</div>
|
||||
<div class="fc-body">
|
||||
<van-field
|
||||
:model-value="form.startDate || ''"
|
||||
label="开始日期"
|
||||
readonly
|
||||
placeholder="请选择开始日期"
|
||||
is-link
|
||||
@click="openStartDatePicker"
|
||||
/>
|
||||
<van-field
|
||||
:model-value="form.startTime || ''"
|
||||
label="开始时间"
|
||||
readonly
|
||||
placeholder="请选择开始时间"
|
||||
is-link
|
||||
@click="openStartTimePicker"
|
||||
/>
|
||||
<van-field
|
||||
:model-value="form.endDate || ''"
|
||||
label="结束日期"
|
||||
readonly
|
||||
placeholder="请先选开始日期"
|
||||
is-link
|
||||
@click="openEndDatePicker"
|
||||
/>
|
||||
<van-field
|
||||
:model-value="form.endTime || ''"
|
||||
label="结束时间"
|
||||
readonly
|
||||
placeholder="请先选结束日期"
|
||||
is-link
|
||||
@click="openEndTimePicker"
|
||||
/>
|
||||
|
||||
<div class="duration-tip" v-if="calcDuration">
|
||||
<van-icon name="info-o" size="14" />
|
||||
<span>预计服务时长:<strong>{{ calcDuration }}</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 服务地点 -->
|
||||
<div class="form-card">
|
||||
<div class="fc-header">
|
||||
<div class="fc-label"><van-icon name="location-o" color="#018fa5" size="16" /> 服务地点</div>
|
||||
<van-tag type="primary" size="medium" plain round @click="useCurrentLocation">使用当前位置</van-tag>
|
||||
</div>
|
||||
<div class="fc-body">
|
||||
<van-field v-model="form.hospitalName" label="医院/地点" placeholder="请输入医院名称或服务地点" />
|
||||
<van-field
|
||||
v-model="form.detailAddress"
|
||||
label="详细地址"
|
||||
type="textarea"
|
||||
rows="2"
|
||||
autosize
|
||||
placeholder="请输入详细地址,如病房号、楼层等"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 护工要求 -->
|
||||
<div class="form-card">
|
||||
<div class="fc-header">
|
||||
<div class="fc-label"><van-icon name="shield-o" color="#018fa5" size="16" /> 护工要求</div>
|
||||
</div>
|
||||
<div class="fc-body">
|
||||
<van-field v-model="form.nurseGender" label="护工性别" readonly placeholder="不限" is-link @click="showNurseGenderPicker = true" />
|
||||
<van-field v-model="form.experienceReq" label="经验要求" readonly placeholder="不限" is-link @click="showExpPicker = true" />
|
||||
<div class="skill-tags-section">
|
||||
<div class="skill-tags-label">特殊技能需求(可多选)</div>
|
||||
<div class="skill-tags-list">
|
||||
<span
|
||||
class="skill-tag"
|
||||
:class="{ 'skill-active': form.skills.includes(skill) }"
|
||||
v-for="(skill, index) in skillOptions"
|
||||
:key="index"
|
||||
@click="toggleSkill(skill)"
|
||||
>{{ skill }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 备注说明 -->
|
||||
<div class="form-card">
|
||||
<div class="fc-header">
|
||||
<div class="fc-label"><van-icon name="edit" color="#018fa5" size="16" /> 备注说明</div>
|
||||
</div>
|
||||
<div class="fc-body">
|
||||
<van-field
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
rows="4"
|
||||
autosize
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
placeholder="请详细描述患者的身体状况、护理需求等特殊情况,以便匹配合适的护工..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 费用预估 -->
|
||||
<div class="form-card price-preview" v-if="estimatedPrice > 0">
|
||||
<div class="price-row">
|
||||
<span class="price-label">费用预估</span>
|
||||
<div class="price-value">
|
||||
<span class="yen">¥</span>
|
||||
<span class="amount">{{ estimatedPrice }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="price-detail">
|
||||
<div class="price-item">
|
||||
<span>基础费用({{ basePrice }}元/小时 x {{ totalHours }}小时)</span>
|
||||
<span>¥{{ basePrice * totalHours }}</span>
|
||||
</div>
|
||||
<div class="price-item" v-if="form.skills.length > 0">
|
||||
<span>技能加成({{ form.skills.length }}项技能 +10%)</span>
|
||||
<span>¥{{ Math.round(basePrice * totalHours * 0.1) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="bottom-bar">
|
||||
<div class="bottom-left">
|
||||
<div class="total-price">
|
||||
<span class="tp-label">预估总价:</span>
|
||||
<span class="tp-value"><span class="tp-yen">¥</span>{{ estimatedPrice || '0' }}</span>
|
||||
</div>
|
||||
<div class="tp-desc">实际价格以接单后确认为准</div>
|
||||
</div>
|
||||
<van-button type="primary" class="submit-btn" round :loading="submitting" @click="submitOrder">
|
||||
发布订单
|
||||
</van-button>
|
||||
</div>
|
||||
|
||||
<!-- 性别选择器 -->
|
||||
<van-popup v-model:show="showGenderPicker" position="bottom" round>
|
||||
<van-picker :columns="genderColumns" @confirm="onGenderConfirm" @cancel="showGenderPicker = false" title="选择性别" />
|
||||
</van-popup>
|
||||
|
||||
<!-- 护工性别选择器 -->
|
||||
<van-popup v-model:show="showNurseGenderPicker" position="bottom" round>
|
||||
<van-picker :columns="nurseGenderColumns" @confirm="onNurseGenderConfirm" @cancel="showNurseGenderPicker = false" title="选择护工性别" />
|
||||
</van-popup>
|
||||
|
||||
<!-- 经验要求选择器 -->
|
||||
<van-popup v-model:show="showExpPicker" position="bottom" round>
|
||||
<van-picker :columns="expColumns" @confirm="onExpConfirm" @cancel="showExpPicker = false" title="选择经验要求" />
|
||||
</van-popup>
|
||||
|
||||
<!-- 开始日期选择器 -->
|
||||
<van-popup v-model:show="showStartDatePicker" position="bottom" round>
|
||||
<van-date-picker
|
||||
:key="'sd-' + startDateKey"
|
||||
v-model="startDatePickerValue"
|
||||
title="选择开始日期"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
@confirm="onStartDateConfirm"
|
||||
@cancel="showStartDatePicker = false"
|
||||
/>
|
||||
</van-popup>
|
||||
|
||||
<!-- 开始时间选择器 -->
|
||||
<van-popup v-model:show="showStartTimePicker" position="bottom" round>
|
||||
<van-time-picker
|
||||
:key="'st-' + startTimeKey"
|
||||
v-model="startTimePickerValue"
|
||||
title="选择开始时间"
|
||||
:columns-type="['hour', 'minute']"
|
||||
@confirm="onStartTimeConfirm"
|
||||
@cancel="showStartTimePicker = false"
|
||||
/>
|
||||
</van-popup>
|
||||
|
||||
<!-- 结束日期选择器 -->
|
||||
<van-popup v-model:show="showEndDatePicker" position="bottom" round>
|
||||
<van-date-picker
|
||||
:key="'ed-' + endDateKey"
|
||||
v-model="endDatePickerValue"
|
||||
title="选择结束日期"
|
||||
:min-date="startMinEndDate"
|
||||
:max-date="maxDate"
|
||||
@confirm="onEndDateConfirm"
|
||||
@cancel="showEndDatePicker = false"
|
||||
/>
|
||||
</van-popup>
|
||||
|
||||
<!-- 结束时间选择器 -->
|
||||
<van-popup v-model:show="showEndTimePicker" position="bottom" round>
|
||||
<van-time-picker
|
||||
:key="'et-' + endTimeKey"
|
||||
v-model="endTimePickerValue"
|
||||
title="选择结束时间"
|
||||
:columns-type="['hour', 'minute']"
|
||||
@confirm="onEndTimeConfirm"
|
||||
@cancel="showEndTimePicker = false"
|
||||
/>
|
||||
</van-popup>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name="js"}
|
||||
<script>
|
||||
const app = Vue.createApp({
|
||||
data() {
|
||||
const now = new Date();
|
||||
return {
|
||||
submitting: false,
|
||||
showGenderPicker: false,
|
||||
showNurseGenderPicker: false,
|
||||
showExpPicker: false,
|
||||
minDate: new Date(),
|
||||
maxDate: new Date(Date.now() + 365 * 86400000),
|
||||
|
||||
// 开始日期选择器
|
||||
showStartDatePicker: false,
|
||||
startDateKey: 0,
|
||||
startDatePickerValue: ['2026', '5', '9'],
|
||||
|
||||
// 开始时间选择器
|
||||
showStartTimePicker: false,
|
||||
startTimeKey: 0,
|
||||
startTimePickerValue: ['8', '0'],
|
||||
|
||||
// 结束日期选择器
|
||||
showEndDatePicker: false,
|
||||
endDateKey: 0,
|
||||
endDatePickerValue: ['2026', '5', '10'],
|
||||
|
||||
// 结束时间选择器
|
||||
showEndTimePicker: false,
|
||||
endTimeKey: 0,
|
||||
endTimePickerValue: ['18', '0'],
|
||||
|
||||
genderColumns: ['男', '女'],
|
||||
nurseGenderColumns: ['不限', '男', '女'],
|
||||
expColumns: ['不限', '1年以上', '3年以上', '5年以上', '8年以上'],
|
||||
|
||||
serviceTypes: [
|
||||
{ value: 'hospital', label: '住院陪护', icon: 'hotel-o', desc: '院内专业护理', color: '#018fa5' },
|
||||
{ value: 'outpatient', label: '门诊陪护', icon: 'guide-o', desc: '陪同就诊检查', color: '#e08c28' },
|
||||
{ value: 'home', label: '居家陪护', icon: 'home-o', desc: '上门居家照料', color: '#2ba245' },
|
||||
{ value: 'maternal', label: '母婴护理', icon: 'like-o', desc: '月子期专业照护', color: '#e91e8b' },
|
||||
],
|
||||
|
||||
skillOptions: ['术后护理', '老年照护', '康复训练', '输液换药', '重症监护', '母婴护理', '营养配餐', '心理疏导', '行动辅助', '中医理疗'],
|
||||
|
||||
form: {
|
||||
serviceType: '',
|
||||
patientName: '',
|
||||
patientPhone: '',
|
||||
patientAge: '',
|
||||
patientGender: '',
|
||||
startDate: '',
|
||||
startTime: '',
|
||||
endDate: '',
|
||||
endTime: '',
|
||||
hospitalName: '',
|
||||
detailAddress: '',
|
||||
nurseGender: '',
|
||||
experienceReq: '',
|
||||
skills: [],
|
||||
remark: '',
|
||||
},
|
||||
|
||||
basePriceMap: {
|
||||
hospital: 68,
|
||||
outpatient: 58,
|
||||
home: 52,
|
||||
maternal: 88,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
startMinEndDate() {
|
||||
if (!this.form.startDate) return this.minDate;
|
||||
const d = new Date(this.form.startDate.replace(/-/g, '/'));
|
||||
return d;
|
||||
},
|
||||
totalHours() {
|
||||
if (!this.form.startDate || !this.form.endDate) return 0;
|
||||
const start = new Date(`${this.form.startDate.replace(/-/g, '/')} ${this.form.startTime || '00:00'}`);
|
||||
const end = new Date(`${this.form.endDate.replace(/-/g, '/')} ${this.form.endTime || '00:00'}`);
|
||||
let diff = (end - start) / 3600000;
|
||||
if (diff <= 0) diff = 0;
|
||||
return Math.round(diff * 10) / 10;
|
||||
},
|
||||
totalDays() {
|
||||
if (!this.form.startDate || !this.form.endDate) return 0;
|
||||
const s = new Date(this.form.startDate.replace(/-/g, '/'));
|
||||
const e = new Date(this.form.endDate.replace(/-/g, '/'));
|
||||
return Math.ceil((e - s) / 86400000);
|
||||
},
|
||||
basePrice() {
|
||||
return this.basePriceMap[this.form.serviceType] || 60;
|
||||
},
|
||||
estimatedPrice() {
|
||||
if (this.totalHours === 0) return 0;
|
||||
let price = this.basePrice * this.totalHours;
|
||||
if (this.form.skills.length > 0) {
|
||||
price = Math.round(price * 1.1);
|
||||
}
|
||||
return price;
|
||||
},
|
||||
calcDuration() {
|
||||
if (!this.form.startDate || !this.form.endDate) return '';
|
||||
const days = this.totalDays;
|
||||
const hours = this.totalHours;
|
||||
if (days <= 0 && hours <= 0) return '';
|
||||
if (days > 0) return `${days}天 ${hours}小时`;
|
||||
return `${hours}小时`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
goBack() { history.back(); },
|
||||
onDraft() { vant.showToast('暂无草稿'); },
|
||||
selectServiceType(type) { this.form.serviceType = type; },
|
||||
useCurrentLocation() {
|
||||
vant.showToast({ message: '正在获取位置...', loading: true, duration: 1500 });
|
||||
setTimeout(() => {
|
||||
this.form.hospitalName = '当前位置附近';
|
||||
vant.clearToast();
|
||||
vant.showToast('已获取位置');
|
||||
}, 1000);
|
||||
},
|
||||
toggleSkill(skill) {
|
||||
const idx = this.form.skills.indexOf(skill);
|
||||
if (idx > -1) {
|
||||
this.form.skills.splice(idx, 1);
|
||||
} else {
|
||||
this.form.skills.push(skill);
|
||||
}
|
||||
},
|
||||
padZero(n) { return String(n).padStart(2, '0'); },
|
||||
openStartDatePicker() {
|
||||
if (this.form.startDate) {
|
||||
const p = this.form.startDate.split('-');
|
||||
this.startDatePickerValue = [p[0], String(parseInt(p[1])), String(parseInt(p[2]))];
|
||||
} else {
|
||||
const now = new Date();
|
||||
this.startDatePickerValue = [
|
||||
String(now.getFullYear()),
|
||||
String(now.getMonth() + 1),
|
||||
String(now.getDate())
|
||||
];
|
||||
}
|
||||
this.startDateKey++;
|
||||
this.showStartDatePicker = true;
|
||||
},
|
||||
openStartTimePicker() {
|
||||
if (!this.form.startDate) {
|
||||
vant.showToast('请先选择开始日期');
|
||||
return;
|
||||
}
|
||||
if (this.form.startTime) {
|
||||
const p = this.form.startTime.split(':');
|
||||
this.startTimePickerValue = [String(parseInt(p[0])), String(parseInt(p[1]))];
|
||||
} else {
|
||||
this.startTimePickerValue = ['8', '0'];
|
||||
}
|
||||
this.startTimeKey++;
|
||||
this.showStartTimePicker = true;
|
||||
},
|
||||
openEndDatePicker() {
|
||||
if (!this.form.startDate) {
|
||||
vant.showToast('请先选择开始日期');
|
||||
return;
|
||||
}
|
||||
if (this.form.endDate) {
|
||||
const p = this.form.endDate.split('-');
|
||||
this.endDatePickerValue = [p[0], String(parseInt(p[1])), String(parseInt(p[2]))];
|
||||
} else {
|
||||
const start = new Date(this.form.startDate.replace(/-/g, '/'));
|
||||
start.setDate(start.getDate() + 1);
|
||||
this.endDatePickerValue = [
|
||||
String(start.getFullYear()),
|
||||
String(start.getMonth() + 1),
|
||||
String(start.getDate())
|
||||
];
|
||||
}
|
||||
this.endDateKey++;
|
||||
this.showEndDatePicker = true;
|
||||
},
|
||||
openEndTimePicker() {
|
||||
if (!this.form.endDate) {
|
||||
vant.showToast('请先选择结束日期');
|
||||
return;
|
||||
}
|
||||
if (this.form.endTime) {
|
||||
const p = this.form.endTime.split(':');
|
||||
this.endTimePickerValue = [String(parseInt(p[0])), String(parseInt(p[1]))];
|
||||
} else {
|
||||
this.endTimePickerValue = ['18', '0'];
|
||||
}
|
||||
this.endTimeKey++;
|
||||
this.showEndTimePicker = true;
|
||||
},
|
||||
onStartDateConfirm({ selectedValues }) {
|
||||
const v = selectedValues;
|
||||
this.form.startDate = `${v[0]}-${this.padZero(v[1])}-${this.padZero(v[2])}`;
|
||||
// 如果已选结束日期早于开始日期,清空结束日期
|
||||
if (this.form.endDate && new Date(this.form.endDate.replace(/-/g, '/')) < new Date(this.form.startDate.replace(/-/g, '/'))) {
|
||||
this.form.endDate = '';
|
||||
this.form.endTime = '';
|
||||
}
|
||||
this.showStartDatePicker = false;
|
||||
},
|
||||
onStartTimeConfirm({ selectedValues }) {
|
||||
const v = selectedValues;
|
||||
this.form.startTime = `${this.padZero(v[0])}:${this.padZero(v[1])}`;
|
||||
this.showStartTimePicker = false;
|
||||
},
|
||||
onEndDateConfirm({ selectedValues }) {
|
||||
const v = selectedValues;
|
||||
this.form.endDate = `${v[0]}-${this.padZero(v[1])}-${this.padZero(v[2])}`;
|
||||
// 校验结束日期不能早于开始日期
|
||||
if (new Date(this.form.endDate.replace(/-/g, '/')) < new Date(this.form.startDate.replace(/-/g, '/'))) {
|
||||
vant.showToast('结束日期不能早于开始日期');
|
||||
this.form.endDate = '';
|
||||
return;
|
||||
}
|
||||
this.showEndDatePicker = false;
|
||||
},
|
||||
onEndTimeConfirm({ selectedValues }) {
|
||||
const v = selectedValues;
|
||||
const endTimeStr = `${this.padZero(v[0])}:${this.padZero(v[1])}`;
|
||||
// 校验结束时间须晚于开始时间
|
||||
if (this.form.endDate === this.form.startDate && this.form.startTime) {
|
||||
const endFull = new Date(`${this.form.endDate.replace(/-/g, '/')} ${endTimeStr}`);
|
||||
const startFull = new Date(`${this.form.startDate.replace(/-/g, '/')} ${this.form.startTime}`);
|
||||
if (endFull <= startFull) {
|
||||
vant.showToast('结束时间须晚于开始时间');
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.form.endTime = endTimeStr;
|
||||
this.showEndTimePicker = false;
|
||||
},
|
||||
onGenderConfirm({ selectedOptions }) { this.form.patientGender = selectedOptions[0]?.text || ''; this.showGenderPicker = false; },
|
||||
onNurseGenderConfirm({ selectedOptions }) { this.form.nurseGender = selectedOptions[0]?.text || ''; this.showNurseGenderPicker = false; },
|
||||
onExpConfirm({ selectedOptions }) { this.form.experienceReq = selectedOptions[0]?.text || ''; this.showExpPicker = false; },
|
||||
formatDateOnly(date) {
|
||||
const y = date.getFullYear();
|
||||
const m = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const d = String(date.getDate()).padStart(2, '0');
|
||||
return `${y}-${m}-${d}`;
|
||||
},
|
||||
validateForm() {
|
||||
if (!this.form.serviceType) { vant.showToast('请选择服务类型'); return false; }
|
||||
if (!this.form.patientName) { vant.showToast('请输入患者姓名'); return false; }
|
||||
if (!this.form.patientPhone) { vant.showToast('请输入联系电话'); return false; }
|
||||
if (!/^1\d{10}$/.test(this.form.patientPhone)) { vant.showToast('手机号格式不正确'); return false; }
|
||||
if (!this.form.startDate || !this.form.startTime) { vant.showToast('请选择开始服务时间'); return false; }
|
||||
if (!this.form.endDate || !this.form.endTime) { vant.showToast('请选择结束服务时间'); return false; }
|
||||
if (this.totalHours <= 0) { vant.showToast('结束时间须晚于开始时间'); return false; }
|
||||
if (!this.form.hospitalName) { vant.showToast('请输入服务地点'); return false; }
|
||||
return true;
|
||||
},
|
||||
submitOrder() {
|
||||
if (!this.validateForm()) return;
|
||||
|
||||
vant.showConfirmDialog({
|
||||
title: '确认发布',
|
||||
message: `服务类型:${this.serviceTypes.find(s => s.value === this.form.serviceType)?.label}\n服务时间:${this.form.startDate} ${this.form.startTime} ~ ${this.form.endDate} ${this.form.endTime}\n服务时长:${this.calcDuration}\n预估费用:¥${this.estimatedPrice}`,
|
||||
confirmButtonText: '确认发布',
|
||||
cancelButtonText: '再想想',
|
||||
}).then(() => {
|
||||
this.submitting = true;
|
||||
setTimeout(() => {
|
||||
this.submitting = false;
|
||||
vant.showDialog({
|
||||
title: '发布成功',
|
||||
message: '订单已发布,系统将为您匹配合适的护工,请耐心等待接单。',
|
||||
confirmButtonText: '查看订单',
|
||||
}).then(() => {
|
||||
window.location.href = '/PatientApp/Order/index';
|
||||
});
|
||||
}, 1500);
|
||||
}).catch(() => {});
|
||||
},
|
||||
},
|
||||
watch: {},
|
||||
});
|
||||
app.use(vant);
|
||||
app.use(vant.Lazyload);
|
||||
app.mount('#app');
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,382 @@
|
||||
{extend name="PatientAPP/layout" /}
|
||||
|
||||
{block name="css"}
|
||||
<link rel="stylesheet" href="/PatientAPP/Order/order.css" />
|
||||
{/block}
|
||||
|
||||
{block name="app"}
|
||||
<div id="app" v-cloak>
|
||||
<!-- 头部区域 -->
|
||||
<div class="header-section">
|
||||
<div class="header-top">
|
||||
<div class="page-title">我的订单</div>
|
||||
<div class="header-actions">
|
||||
<div class="icon-btn" @click="onSearch">
|
||||
<van-icon name="search" size="17" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab标签栏 -->
|
||||
<van-tabs v-model:active="activeTab" swipeable sticky :offset-top="0" color="#fff" line-width="20" line-height="3">
|
||||
<van-tab title="全部" name="all"></van-tab>
|
||||
<van-tab title="待接单" name="pending"></van-tab>
|
||||
<van-tab title="进行中" name="ongoing"></van-tab>
|
||||
<van-tab title="已完成" name="completed"></van-tab>
|
||||
<van-tab title="已取消" name="cancelled"></van-tab>
|
||||
</van-tabs>
|
||||
</div>
|
||||
|
||||
<!-- 订单列表 -->
|
||||
<div class="order-list-wrapper">
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list
|
||||
v-model:loading="loading"
|
||||
:finished="finished"
|
||||
finished-text="没有更多了"
|
||||
@load="onLoad"
|
||||
>
|
||||
<div class="order-card" v-for="(order, index) in filteredOrders" :key="order.id" @click="viewOrder(order)">
|
||||
<!-- 卡片头部:状态 + 订单号 + 时间 -->
|
||||
<div class="oc-top">
|
||||
<div class="oc-top-left">
|
||||
<span class="oc-status-dot" :class="'dot-' + order.status"></span>
|
||||
<span class="oc-status-text" :class="'text-' + order.status">{{ order.statusText }}</span>
|
||||
<span class="oc-no">{{ order.orderNo }}</span>
|
||||
</div>
|
||||
<span class="oc-time">{{ order.createTime }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 核心信息区 -->
|
||||
<div class="oc-main">
|
||||
<!-- 左侧服务类型图标 -->
|
||||
<div class="oc-service-icon" :class="'icon-' + order.status">
|
||||
<van-icon :name="serviceIcon(order.serviceType)" size="24" />
|
||||
</div>
|
||||
<!-- 右侧详情 -->
|
||||
<div class="oc-detail">
|
||||
<div class="oc-title-row">
|
||||
<span class="oc-service-type">{{ order.serviceType }}</span>
|
||||
<van-tag v-if="order.status === 'ongoing'" type="primary" size="medium" round>服务中</van-tag>
|
||||
<van-tag v-if="order.status === 'pending'" color="#fef4ec" text-color="#e08c28" size="medium" round>等待接单</van-tag>
|
||||
</div>
|
||||
<div class="oc-meta-row">
|
||||
<div class="oc-meta-item">
|
||||
<van-icon name="clock-o" size="14" />
|
||||
<span>{{ order.serviceTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oc-meta-row">
|
||||
|
||||
</div>
|
||||
<div class="oc-meta-row">
|
||||
<div class="oc-meta-item">
|
||||
<van-icon name="location-o" size="14" />
|
||||
<span class="oc-location">{{ order.location }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 护工信息条 -->
|
||||
<div class="oc-nurse-bar" v-if="order.nurseName" @click.stop="togglePhone(order)">
|
||||
<div class="nurse-avatar-sm">
|
||||
<van-icon name="contact" size="14" />
|
||||
</div>
|
||||
<span class="nurse-name-sm">{{ order.nurseName }}</span>
|
||||
<span class="nurse-exp-sm">· {{ order.nurseExp }}年经验</span>
|
||||
<span class="nurse-phone-sm">
|
||||
{{ order.showPhone ? order.nursePhone : order.nursePhoneHidden }}
|
||||
<van-icon :name="order.showPhone ? 'eye-o' : 'closed-eye'" size="12" style="margin-left:4px;vertical-align:middle;" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 备注预览 -->
|
||||
<div class="oc-remark" v-if="order.remark">
|
||||
<!-- <van-icon name="chat-o" size="13" /> -->
|
||||
<span style="color: #cc6600;font-weight: 600;">订单备注:</span>
|
||||
<span>{{ order.remark }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="oc-bottom">
|
||||
<div class="oc-price-block">
|
||||
<span class="oc-price-label">实付金额</span>
|
||||
<div class="oc-price-value">
|
||||
<span class="oc-yen">¥</span>
|
||||
<span class="oc-amount">{{ order.totalAmount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oc-actions">
|
||||
<van-button
|
||||
v-if="order.status === 'pending'"
|
||||
size="small"
|
||||
round
|
||||
plain
|
||||
hairline
|
||||
@click.stop="cancelOrder(order)"
|
||||
>取消订单</van-button>
|
||||
<template v-if="order.status === 'ongoing'">
|
||||
<van-button
|
||||
size="small"
|
||||
round
|
||||
plain
|
||||
hairline
|
||||
type="primary"
|
||||
@click.stop="extendOrder(order)"
|
||||
>延长服务</van-button>
|
||||
<van-button
|
||||
size="small"
|
||||
round
|
||||
type="primary"
|
||||
@click.stop="contactNurse(order)"
|
||||
>联系护工</van-button>
|
||||
</template>
|
||||
<template v-if="order.status === 'completed' && !order.reviewed">
|
||||
<van-button
|
||||
size="small"
|
||||
round
|
||||
plain
|
||||
hairline
|
||||
@click.stop="viewOrder(order)"
|
||||
>查看详情</van-button>
|
||||
<van-button
|
||||
size="small"
|
||||
round
|
||||
type="success"
|
||||
@click.stop="reviewOrder(order)"
|
||||
>去评价</van-button>
|
||||
</template>
|
||||
<template v-if="order.status === 'completed' && order.reviewed">
|
||||
<van-button
|
||||
size="small"
|
||||
round
|
||||
plain
|
||||
hairline
|
||||
@click.stop="viewReview(order)"
|
||||
>查看评价</van-button>
|
||||
</template>
|
||||
<template v-if="order.status === 'cancelled'">
|
||||
<van-button
|
||||
size="small"
|
||||
round
|
||||
plain
|
||||
hairline
|
||||
@click.stop="reorder(order)"
|
||||
>再次下单</van-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<van-empty
|
||||
v-if="!loading && filteredOrders.length === 0"
|
||||
description="暂无订单记录"
|
||||
image="search"
|
||||
>
|
||||
<van-button round type="primary" size="small" class="empty-btn" @click="goPublish">立即下单</van-button>
|
||||
</van-empty>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
|
||||
<!-- 搜索弹窗 -->
|
||||
<van-popup v-model:show="showSearch" position="top" :style="{ height: 'auto' }">
|
||||
<van-search
|
||||
v-model="searchKeyword"
|
||||
placeholder="搜索订单号/服务类型/地点"
|
||||
shape="round"
|
||||
show-action
|
||||
@search="doSearch"
|
||||
@cancel="showSearch = false"
|
||||
>
|
||||
<template #action>
|
||||
<div @click="doSearch">搜索</div>
|
||||
</template>
|
||||
</van-search>
|
||||
</van-popup>
|
||||
|
||||
<!-- 底部栏 -->
|
||||
{include file="PatientAPP/Component/van-tabbar" /}
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name="js"}
|
||||
<script>
|
||||
const app = Vue.createApp({
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'all',
|
||||
showSearch: false,
|
||||
searchKeyword: '',
|
||||
refreshing: false,
|
||||
loading: false,
|
||||
finished: true,
|
||||
stats: { pending: 2, ongoing: 1, completed: 8 },
|
||||
orderList: [
|
||||
{
|
||||
id: 1, orderNo: 'MC20260509001', status: 'ongoing', statusText: '进行中',
|
||||
createTime: '2026-05-08 14:30', serviceType: '住院陪护',
|
||||
serviceTime: '2026-05-08 15:00 ~ 2026-05-11 15:00 (3天)',
|
||||
location: '北京协和医院 住院部12楼1205病房',
|
||||
nurseName: '张秀芳', nurseExp: 8, nurseRating: 4.9,
|
||||
nursePhone: '13812345678', nursePhoneHidden: '138****5678', showPhone: false,
|
||||
remark: '术后护理,需要协助翻身、拍背,注意引流管',
|
||||
totalAmount: 2448, reviewed: false,
|
||||
},
|
||||
{
|
||||
id: 2, orderNo: 'MC20260508002', status: 'pending', statusText: '待接单',
|
||||
createTime: '2026-05-09 10:00', serviceType: '门诊陪护',
|
||||
serviceTime: '2026-05-10 08:30 ~ 12:30 (半天)',
|
||||
location: '北京大学第一医院 门诊楼3层',
|
||||
nurseName: '', nurseExp: '', nurseRating: '',
|
||||
remark: '陪同就诊,协助挂号、缴费、取药',
|
||||
totalAmount: 196, reviewed: false,
|
||||
},
|
||||
{
|
||||
id: 3, orderNo: 'MC20260507003', status: 'pending', statusText: '待接单',
|
||||
createTime: '2026-05-07 16:20', serviceType: '居家陪护',
|
||||
serviceTime: '2026-05-10 09:00 ~ 17:00 (1天)',
|
||||
location: '北京市朝阳区建国路88号院3号楼2单元501',
|
||||
nurseName: '', nurseExp: '', nurseRating: '',
|
||||
remark: '老人日常照料,做饭、打扫卫生、陪同散步',
|
||||
totalAmount: 520, reviewed: false,
|
||||
},
|
||||
{
|
||||
id: 4, orderNo: 'MC20260505004', status: 'completed', statusText: '已完成',
|
||||
createTime: '2026-05-03 09:15', serviceType: '住院陪护',
|
||||
serviceTime: '2026-05-03 10:00 ~ 2026-05-06 10:00 (3天)',
|
||||
location: '中日友好医院 住院部8楼802病房',
|
||||
nurseName: '李国华', nurseExp: 10, nurseRating: 4.8,
|
||||
nursePhone: '13987654321', nursePhoneHidden: '139****4321', showPhone: false,
|
||||
remark: '重症监护后转普通病房的康复期护理',
|
||||
totalAmount: 2700, reviewed: true,
|
||||
},
|
||||
{
|
||||
id: 5, orderNo: 'MC20260430005', status: 'completed', statusText: '已完成',
|
||||
createTime: '2026-04-28 11:40', serviceType: '母婴护理',
|
||||
serviceTime: '2026-04-29 08:00 ~ 2026-05-13 08:00 (14天)',
|
||||
location: '北京妇产医院 家庭住所(朝阳区望京)',
|
||||
nurseName: '王美玲', nurseExp: 5, nurseRating: 4.9,
|
||||
nursePhone: '13666668888', nursePhoneHidden: '3666668888', showPhone: false,
|
||||
remark: '月子期间母婴护理,新生儿照料和产妇恢复',
|
||||
totalAmount: 11200, reviewed: true,
|
||||
},
|
||||
{
|
||||
id: 6, orderNo: 'MC20260425006', status: 'completed', statusText: '已完成',
|
||||
createTime: '2026-04-23 15:00', serviceType: '门诊陪护',
|
||||
serviceTime: '2026-04-25 07:30 ~ 13:00 (半天)',
|
||||
location: '首都医科大学附属北京天坛医院',
|
||||
nurseName: '陈建国', nurseExp: 6, nurseRating: 4.7,
|
||||
nursePhone: '15811112222', nursePhoneHidden: '158****2222', showPhone: false,
|
||||
remark: '陪同做核磁共振检查,老人行动不便需轮椅辅助',
|
||||
totalAmount: 232, reviewed: false,
|
||||
},
|
||||
{
|
||||
id: 7, orderNo: 'MC20260420007', status: 'cancelled', statusText: '已取消',
|
||||
createTime: '2026-04-18 09:30', serviceType: '居家陪护',
|
||||
serviceTime: '2026-04-20 14:00 ~ 18:00 (4小时)',
|
||||
location: '北京市海淀区中关村大街1号',
|
||||
nurseName: '', nurseExp: '', nurseRating: '',
|
||||
remark: '临时有事取消了',
|
||||
totalAmount: 240, reviewed: false,
|
||||
},
|
||||
{
|
||||
id: 8, orderNo: 'MC20260415008', status: 'completed', statusText: '已完成',
|
||||
createTime: '2026-04-13 10:20', serviceType: '住院陪护',
|
||||
serviceTime: '2026-04-15 08:00 ~ 2026-04-18 08:00 (3天)',
|
||||
location: '中国人民解放军总医院(301医院) 住院部东楼608',
|
||||
nurseName: '赵文斌', nurseExp: 12, nurseRating: 4.8,
|
||||
nursePhone: '17799887766', nursePhoneHidden: '177****7766', showPhone: false,
|
||||
remark: '心脏手术后康复护理,监测生命体征',
|
||||
totalAmount: 2880, reviewed: true,
|
||||
},
|
||||
{
|
||||
id: 9, orderNo: 'MC20260410009', status: 'completed', statusText: '已完成',
|
||||
createTime: '2026-04-08 14:00', serviceType: '门诊陪护',
|
||||
serviceTime: '2026-04-10 09:00 ~ 11:30 (2.5小时)',
|
||||
location: '北京安贞医院 心脏中心',
|
||||
nurseName: '刘晓红', nurseExp: 3, nurseRating: 4.6,
|
||||
remark: '陪同复查心电图和超声心动图',
|
||||
totalAmount: 138, reviewed: true,
|
||||
},
|
||||
{
|
||||
id: 10, orderNo: 'MC20260405010', status: 'completed', statusText: '已完成',
|
||||
createTime: '2026-04-02 16:45', serviceType: '居家陪护',
|
||||
serviceTime: '2026-04-05 09:00 ~ 18:00 (连续5天)',
|
||||
location: '北京市丰台区方庄南路18号院',
|
||||
nurseName: '周明辉', nurseExp: 7, nurseRating: 4.7,
|
||||
remark: '脑梗塞后遗症患者居家康复训练和生活照料',
|
||||
totalAmount: 2250, reviewed: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
filteredOrders() {
|
||||
let list = this.orderList;
|
||||
if (this.activeTab !== 'all') {
|
||||
list = list.filter(o => o.status === this.activeTab);
|
||||
}
|
||||
if (this.searchKeyword) {
|
||||
const kw = this.searchKeyword.toLowerCase();
|
||||
list = list.filter(o =>
|
||||
o.orderNo.toLowerCase().includes(kw) ||
|
||||
o.serviceType.includes(kw) ||
|
||||
o.location.includes(kw) ||
|
||||
(o.nurseName && o.nurseName.includes(kw))
|
||||
);
|
||||
}
|
||||
return list;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onSearch() { this.showSearch = true; },
|
||||
doSearch() { this.showSearch = false; vant.showToast({ message: `搜索: ${this.searchKeyword}`, position: 'top' }); },
|
||||
switchTab(tab) { this.activeTab = tab; },
|
||||
onRefresh() { setTimeout(() => { this.refreshing = false; vant.showToast('刷新成功'); }, 1000); },
|
||||
onLoad() { this.loading = false; this.finished = true; },
|
||||
togglePhone(order) { order.showPhone = !order.showPhone; },
|
||||
viewOrder(order) { vant.showDialog({ title: '订单详情', message: `订单号: ${order.orderNo}\n服务: ${order.serviceType}\n时间: ${order.serviceTime}\n金额: ¥${order.totalAmount}\n状态: ${order.statusText}` }); },
|
||||
cancelOrder(order) {
|
||||
vant.showConfirmDialog({ title: '确认取消', message: '确定要取消该订单吗?取消后需重新下单。' }).then(() => {
|
||||
order.status = 'cancelled';
|
||||
order.statusText = '已取消';
|
||||
this.stats.pending--;
|
||||
vant.showToast({ message: '订单已取消', icon: 'success' });
|
||||
}).catch(() => {});
|
||||
},
|
||||
contactNurse(order) {
|
||||
vant.showDialog({ title: '联系护工', message: `正在呼叫 ${order.nurseName}...\n电话: 138****8888` });
|
||||
},
|
||||
extendOrder(order) {
|
||||
vant.showConfirmDialog({ title: '延长服务', message: '确定要延长当前服务时长吗?护工将收到延长时间通知。' }).then(() => {
|
||||
vant.showToast({ message: '已发送延长请求', icon: 'success' });
|
||||
}).catch(() => {});
|
||||
},
|
||||
reviewOrder(order) {
|
||||
vant.showDialog({ title: '服务评价', message: '评价功能开发中...' });
|
||||
},
|
||||
viewReview(order) {
|
||||
vant.showToast('查看评价详情');
|
||||
},
|
||||
reorder(order) {
|
||||
vant.showToast({ message: '正在跳转到下单页面...', icon: 'success' });
|
||||
},
|
||||
goPublish() {
|
||||
vant.showToast('跳转到发布订单页');
|
||||
},
|
||||
serviceIcon(type) {
|
||||
const map = { '住院陪护': 'hotel-o', '门诊陪护': 'guide-o', '居家陪护': 'home-o', '母婴护理': 'like-o' };
|
||||
return map[type] || 'service-o';
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
activeTab(val) { if (val !== 'orders') { onTabBarChange(val); } },
|
||||
},
|
||||
});
|
||||
app.use(vant);
|
||||
app.use(vant.Lazyload);
|
||||
app.mount('#app');
|
||||
</script>
|
||||
{/block}
|
||||
Reference in New Issue
Block a user