CareSummaryDrawer.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <template>
  2. <el-drawer
  3. :model-value="visible"
  4. @update:model-value="updateVisible"
  5. title="宠物护理工作小结"
  6. direction="rtl"
  7. size="750px"
  8. destroy-on-close
  9. class="care-summary-drawer"
  10. >
  11. <div class="care-summary-container" v-if="order">
  12. <!-- Pet Header -->
  13. <div class="summary-header">
  14. <div class="avatar-wrapper">
  15. <el-avatar :size="80" :src="order.petAvatar" shape="circle" class="pet-summary-avatar">{{ order.petName?.charAt(0) }}</el-avatar>
  16. </div>
  17. <div class="pet-summary-info">
  18. <div class="summary-name-row">
  19. <span class="name">{{ order.petName }}</span>
  20. <div class="tags-group">
  21. <el-tag :type="order.petGender==='male'?'':'danger'" effect="light" round>
  22. <el-icon><component :is="order.petGender==='male'?'Male':'Female'" /></el-icon>
  23. {{ order.petAge }}
  24. </el-tag>
  25. <el-tag v-for="tag in (order.petTags||[])" :key="tag" type="warning" effect="plain" round>{{ tag }}</el-tag>
  26. </div>
  27. </div>
  28. <div class="summary-sub-row">
  29. <div class="info-item">
  30. <span class="lbl">品种</span>
  31. <span class="val">{{ order.petBreed || '未知' }}</span>
  32. </div>
  33. <div class="divider-v"></div>
  34. <div class="info-item">
  35. <span class="lbl">体重</span>
  36. <span class="val">{{ order.petWeight }}</span>
  37. </div>
  38. <div class="divider-v"></div>
  39. <div class="info-item">
  40. <span class="lbl">主人</span>
  41. <span class="val">{{ order.userName || '未知' }}</span>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. <!-- Info Groups -->
  47. <div class="summary-section">
  48. <div class="sec-title">
  49. <span class="icon-box"><el-icon><List /></el-icon></span>
  50. 基本信息
  51. </div>
  52. <el-descriptions :column="2" border class="spacious-desc">
  53. <el-descriptions-item label="性格关键词">{{ order.petPersonality }}</el-descriptions-item>
  54. <el-descriptions-item label="健康状况">
  55. <el-tag :type="order.healthStatus==='健康'?'success':'danger'" effect="light" size="small">{{ order.healthStatus }}</el-tag>
  56. </el-descriptions-item>
  57. <el-descriptions-item label="疫苗情况">
  58. <div class="flex-align">
  59. <span style="color:#67c23a; margin-right:8px;" v-if="order.vaccineImg"><el-icon><CircleCheckFilled /></el-icon> 已接种</span>
  60. <span v-else style="color:#909399;">未接种</span>
  61. <el-image
  62. v-if="order.vaccineImg"
  63. style="width: 24px; height: 24px; border-radius:4px; vertical-align:middle; cursor:zoom-in;"
  64. :src="order.vaccineImg"
  65. :preview-src-list="[order.vaccineImg]"
  66. :preview-teleported="true"
  67. />
  68. </div>
  69. </el-descriptions-item>
  70. <el-descriptions-item label="过敏史">
  71. <span :style="{color: order.allergy ? '#f56c6c' : 'inherit'}">{{ order.allergy || '无' }}</span>
  72. </el-descriptions-item>
  73. </el-descriptions>
  74. </div>
  75. <div class="summary-section">
  76. <div class="sec-title">
  77. <span class="icon-box text-blue"><el-icon><HomeFilled /></el-icon></span>
  78. 服务环境
  79. </div>
  80. <el-descriptions :column="2" border class="spacious-desc">
  81. <el-descriptions-item label="到家时间">{{ order.homeTime }}</el-descriptions-item>
  82. <el-descriptions-item label="房屋类型">{{ order.houseType }}</el-descriptions-item>
  83. <el-descriptions-item label="入户方式" :span="2">
  84. <span style="font-weight:bold;">{{ order.entryMethod }}</span>
  85. <span style="margin-left:8px; color:#909399;">({{ order.entryDetail }})</span>
  86. </el-descriptions-item>
  87. </el-descriptions>
  88. </div>
  89. <!-- Service Log -->
  90. <div class="summary-section main-log">
  91. <div class="sec-title" style="border:none; padding-left:0; margin-bottom:16px;">
  92. <div class="left">
  93. <span class="icon-box text-orange"><el-icon><Notebook /></el-icon></span>
  94. 服务内容记录
  95. </div>
  96. <el-button v-if="!isEditingSummary" type="primary" link icon="Edit" @click="isEditingSummary = true">编辑</el-button>
  97. </div>
  98. <div v-if="isEditingSummary" class="edit-area">
  99. <el-input
  100. v-model="careSummaryText"
  101. type="textarea"
  102. :rows="12"
  103. placeholder="请输入详细的护理服务小结..."
  104. resize="none"
  105. />
  106. <div class="edit-actions">
  107. <el-button @click="isEditingSummary = false">取消</el-button>
  108. <el-button type="primary" @click="saveCareSummary">保存内容</el-button>
  109. </div>
  110. </div>
  111. <div v-else class="log-content-box">
  112. <pre class="log-text">{{ careSummaryText }}</pre>
  113. </div>
  114. </div>
  115. <!-- Footer Info -->
  116. <div class="summary-footer">
  117. <div class="footer-info">
  118. <div class="f-row">
  119. <span class="lbl">护宠师</span>
  120. <span class="val user-active">{{ order.fulfillerName || '当前履约者' }}</span>
  121. </div>
  122. <div class="f-row">
  123. <span class="lbl">提交时间</span>
  124. <span class="val">{{ order.summaryTime || '2024-02-04 17:00' }}</span>
  125. </div>
  126. </div>
  127. <div class="footer-action">
  128. <el-button size="large" @click="updateVisible(false)">关闭</el-button>
  129. </div>
  130. </div>
  131. </div>
  132. </el-drawer>
  133. </template>
  134. <script setup>
  135. import { ref, watch } from 'vue'
  136. import { ElMessage } from 'element-plus'
  137. const props = defineProps({
  138. visible: Boolean,
  139. order: Object
  140. })
  141. const emit = defineEmits(['update:visible', 'success'])
  142. const isEditingSummary = ref(false)
  143. const careSummaryText = ref('')
  144. watch(() => props.visible, (val) => {
  145. if (val && props.order) {
  146. isEditingSummary.value = false
  147. if (!props.order.careSummary) {
  148. careSummaryText.value = `1. 精神/身体状态:${props.order.petName}精神状态良好,愿意互动。
  149. 2. 进食/饮水:食欲正常,饮水适当,已清洗碗具。
  150. 3. 排泄情况:排便正常,颜色形状正常,已清理。
  151. 4. 卫生情况:猫砂盆/地面已清理干净,无异味。
  152. 5. 互动情况:陪玩了20分钟,${props.order.petName}很开心。
  153. 6. 特殊情况/备注:无特殊异常。`
  154. } else {
  155. careSummaryText.value = props.order.careSummary
  156. }
  157. }
  158. })
  159. const updateVisible = (val) => {
  160. emit('update:visible', val)
  161. }
  162. const saveCareSummary = () => {
  163. if (props.order) {
  164. props.order.careSummary = careSummaryText.value
  165. if (!props.order.summaryTime) {
  166. props.order.summaryTime = '2024-02-04 17:00'
  167. }
  168. ElMessage.success('护理小结已保存')
  169. isEditingSummary.value = false
  170. emit('success', careSummaryText.value)
  171. }
  172. }
  173. </script>
  174. <style scoped>
  175. /* Enhanced Care Summary Styles */
  176. .care-summary-drawer :deep(.el-drawer__header) { margin-bottom: 0; padding: 20px 24px; border-bottom: 1px solid #f0f0f0; }
  177. .care-summary-drawer :deep(.el-drawer__body) { padding: 0; overflow-y: auto; background: #fff; }
  178. .care-summary-container { padding: 32px 40px; }
  179. /* 1. Header */
  180. .summary-header { display: flex; gap: 24px; align-items: flex-start; margin-bottom: 32px; padding-bottom: 24px; border-bottom: 1px dashed #e4e7ed; }
  181. .avatar-wrapper { border: 4px solid #f2f6fc; border-radius: 50%; }
  182. .pet-summary-info { flex: 1; display:flex; flex-direction:column; gap:12px; padding-top: 4px; }
  183. .summary-name-row { display: flex; align-items: center; gap: 16px; margin-bottom: 4px; }
  184. .summary-name-row .name { font-size: 24px; font-weight: 800; color: #303133; letter-spacing: 0.5px; }
  185. .tags-group { display: flex; gap: 8px; align-items: center; }
  186. .summary-sub-row { display: flex; align-items: center; background: #f9fafe; padding: 10px 16px; border-radius: 8px; align-self: flex-start; }
  187. .info-item { display: flex; flex-direction: column; gap: 2px; }
  188. .info-item .lbl { font-size: 11px; color: #909399; text-transform: uppercase; }
  189. .info-item .val { font-size: 14px; font-weight: bold; color: #606266; }
  190. .divider-v { width: 1px; height: 24px; background: #ebeef5; margin: 0 16px; }
  191. /* 2. Sections */
  192. .summary-section { margin-bottom: 40px; }
  193. .sec-title {
  194. font-size: 16px; font-weight: 700; color: #303133; margin-bottom: 16px;
  195. display:flex; align-items:center; gap:8px;
  196. justify-content: space-between;
  197. }
  198. .sec-title .left { display: flex; align-items: center; gap: 8px; }
  199. .icon-box {
  200. width: 28px; height: 28px; background: #ecf5ff; color: #409eff; border-radius: 6px;
  201. display: flex; align-items: center; justify-content: center; font-size: 16px;
  202. }
  203. .icon-box.text-blue { background: #ecf5ff; color: #409eff; }
  204. .icon-box.text-orange { background: #fdf6ec; color: #e6a23c; }
  205. /* 3. Descriptions */
  206. .spacious-desc :deep(.el-descriptions__cell) { padding: 12px 16px!important; }
  207. .spacious-desc :deep(.el-descriptions__label) { width: 100px; color: #606266; font-weight: 500; background: #fafafa; }
  208. .flex-align { display: flex; align-items: center; }
  209. /* 4. Log Area */
  210. .main-log { background: #fff; }
  211. .log-content-box {
  212. background: #fff;
  213. border: 1px solid #ebeef5; border-radius: 8px;
  214. padding: 24px;
  215. box-shadow: 0 2px 12px rgba(0,0,0,0.02);
  216. position: relative;
  217. }
  218. .log-content-box::before {
  219. content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: #e6a23c; border-top-left-radius: 8px; border-bottom-left-radius: 8px;
  220. }
  221. .log-text {
  222. white-space: pre-wrap; font-family: 'Inter', system-ui, sans-serif; margin: 0; line-height: 1.8; font-size: 15px; color: #303133; text-align: justify;
  223. }
  224. .edit-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 12px; }
  225. /* 5. Footer */
  226. .summary-footer {
  227. margin-top: 60px; padding-top: 24px; border-top: 1px solid #ebeef5;
  228. display: flex; justify-content: space-between; align-items: center;
  229. }
  230. .footer-info { display: flex; gap: 32px; }
  231. .f-row { display: flex; flex-direction: column; gap: 4px; }
  232. .f-row .lbl { font-size: 12px; color: #909399; }
  233. .f-row .val { font-size: 15px; font-weight: 600; color: #303133; }
  234. .f-row .val.user-active { color: #409eff; }
  235. </style>