console.uvue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. <template>
  2. <!-- #ifdef APP -->
  3. <scroll-view style="flex:1">
  4. <!-- #endif -->
  5. <view class="container">
  6. <!-- 背景图改为absolute,避免fixed在scroll-view内的问题 -->
  7. <image class="bg-image" src="@/static/imagesInfo/bg-color.png" mode="aspectFill" />
  8. <scroll-view style="flex: 1" scroll-y>
  9. <view class="page">
  10. <!-- 城市信息 -->
  11. <view class="city-info">
  12. <text class="city-text-box">当前城市:{{ state.cityInfo }}</text>
  13. <u-icon name="notification" :size="24" />
  14. </view>
  15. <!-- 用户卡片 -->
  16. <view class="user-card">
  17. <image class="user-bg" src="@/static/imagesInfo/bg-icon.png" mode="scaleToFill" />
  18. <view class="user-content" style="padding: 20rpx;">
  19. <!-- 左侧信息 -->
  20. <view class="user-left">
  21. <view class="user-row">
  22. <text class="user-name">{{ coachInfo.nickname }}</text>
  23. <view class="tags">
  24. <text class="tag-new">新人实习</text>
  25. </view>
  26. <u-icon name="edit" :size="18" @click="jumpMasterInfo" />
  27. <text class="tag">编辑</text>
  28. </view>
  29. <view class="user-row">
  30. <u-icon name="customer-interests" :size="18" />
  31. <text class="user-role">{{ coachInfo.role_name }}</text>
  32. <u-icon name="store" :size="18" />
  33. <text class="user-shop">{{ coachInfo.shop_name }}</text>
  34. </view>
  35. <view class="online-switch">
  36. <u-switch :checked="state.isOnline" @change="toggleOnline" />
  37. </view>
  38. </view>
  39. <!-- 右侧头像 -->
  40. <view class="user-right" @click="jumpMasterInfo">
  41. <text class="time-text">入驻时间</text>
  42. <text class="time-text" style="margin-top: 5rpx;">{{ displayCreatedAt }}</text>
  43. <image class="avatar-img" :src="coachInfo.avatar" mode="aspectFit" />
  44. </view>
  45. </view>
  46. <!-- 定位栏 -->
  47. <view class="location-bar">
  48. <u-icon name="navigation" :size="18" />
  49. <text class="location-text">当前定位:{{ userLocation }}</text>
  50. <text class="location-btn" @click="updateLocation">手动更新</text>
  51. </view>
  52. </view>
  53. <!-- 本月数据 -->
  54. <view class="stats-row">
  55. <view class="stat-item" v-for="(item, index) in monthStats" :key="index">
  56. <!-- {{item?.["label"]}} -->
  57. <text class="stat-label">{{ item?.["label"] }}</text>
  58. <text class="stat-value">{{ item?.["value"]}}</text>
  59. </view>
  60. </view>
  61. <!-- 功能按钮 -->
  62. <view class="func-grid">
  63. <view class="func-item" v-for="(item, index) in funcList" :key="index"
  64. @click="jumpSetProject(item.label)">
  65. <image class="func-icon" :src="item.iconUrl" mode="aspectFit" />
  66. <text class="func-label">{{ item.label }}</text>
  67. </view>
  68. </view>
  69. <!-- 数据统计 -->
  70. <view class="data-section">
  71. <view class="section-header">
  72. <text class="section-title">数据统计</text>
  73. <text class="section-more" @click="jumpStatisics">查看全部 ></text>
  74. </view>
  75. <view class="data-grid">
  76. <view class="data-item" v-for="(item, index) in coachData" :key="index">
  77. <text class="data-value">{{ item?.["value"] }}</text>
  78. <text class="data-label">{{ item?.["label"] }}</text>
  79. </view>
  80. </view>
  81. </view>
  82. <!-- 客户评价 -->
  83. <view class="eval-section">
  84. <view class="section-header">
  85. <text class="section-title">客户评价</text>
  86. <text class="section-more" @click="jumpAppraise">查看全部 ></text>
  87. </view>
  88. <scroll-view class="eval-tags" scroll-x>
  89. <text class="eval-tag" v-for="(tag, index) in evalTags" :key="index">
  90. {{ tag?.["text"] }} {{ (tag?.["count"])as number > 0 ? tag?.["count"] : '' }}
  91. </text>
  92. </scroll-view>
  93. <view class="eval-item" v-for="(item, index) in evalList" :key="index">
  94. <image class="eval-avatar" :src='(item["user_info"] as UTSJSONObject)?.["avatar"] as string'
  95. mode="aspectFill" />
  96. <view class="eval-content">
  97. <view class="eval-top">
  98. <text
  99. class="eval-name">{{(item['user_info'] as UTSJSONObject)?.['nickname'] as string}}</text>
  100. <text class="eval-date">{{item?.["created_at"] as string}}</text>
  101. </view>
  102. <view class="eval-stars">
  103. <text>⭐⭐⭐⭐⭐</text>
  104. <text class="eval-service">{{item?.["project_name"]}}</text>
  105. </view>
  106. <view style="flex-direction: row;">
  107. <text class="eval-comment" v-for='(tag, index) in (item?.["tags_list"]) as string[]'
  108. :key="index">
  109. {{tag}}
  110. </text>
  111. </view>
  112. </view>
  113. </view>
  114. </view>
  115. <!-- 底部留白,避免悬浮球遮挡 -->
  116. <!-- <view style="height: 100rpx;"></view> -->
  117. </view>
  118. </scroll-view>
  119. <!-- 悬浮球移到scroll-view外 -->
  120. <u-floating @click="callPolice" />
  121. </view>
  122. <!-- #ifdef APP -->
  123. </scroll-view>
  124. <!-- #endif -->
  125. </template>
  126. <script setup lang="uts">
  127. import { ref, computed, reactive, } from 'vue'
  128. import { getCoachDetaile } from '@/utils/api/masterInfoApi'
  129. import { getCommentList } from '@/utils/api/order'
  130. import { getMonthData, getAllData, getCoachWorkState, editCoachWorkState, editWorkTimeSetting } from '@/utils/api/workbenches'
  131. // ==================== 类型定义 ====================
  132. type CoachInfo = {
  133. nickname : string
  134. role_name : string
  135. shop_name : string
  136. created_at : string
  137. avatar : string
  138. coach : string
  139. }
  140. type State = {
  141. isOnline : boolean
  142. cityInfo : string
  143. }
  144. type FuncItem = {
  145. label : string
  146. iconUrl : string
  147. }
  148. type EvalTag = {
  149. text : string
  150. count : number
  151. }
  152. type StatItem = {
  153. label : string,
  154. value : string | number
  155. }
  156. type UserInfo = {
  157. nickname ?: string
  158. avatar ?: string
  159. }
  160. type EvalItem = {
  161. user_info ?: UserInfo
  162. created_at ?: string
  163. project_name ?: string
  164. tags_list ?: string[]
  165. }
  166. // ==================== 响应式数据(全部使用reactive/ref,避免shallowRef)====================
  167. const state = ref<State>({
  168. isOnline: true,
  169. cityInfo: '定位中...'
  170. })
  171. const coachInfo = reactive<CoachInfo>({
  172. nickname: '',
  173. role_name: '小丁理疗师',
  174. shop_name: '未绑定门店',
  175. created_at: '',
  176. avatar: '/static/testInfo/boy-nickname.png',
  177. coach: ''
  178. })
  179. const userLocation = ref<string>('')
  180. const displayCreatedAt = computed(() : string => {
  181. const date = coachInfo.created_at
  182. if (date == null || date.length == 0) {
  183. return '--'
  184. }
  185. return date
  186. })
  187. // ==================== 静态数据 ====================
  188. const monthStats = ref<UTSArray<UTSJSONObject>>([
  189. { label: '本月收益(元)', value: '2234.88' },
  190. { label: '本月接单量(单)', value: '2234.88' },
  191. { label: '本月退单率', value: '30%' }
  192. ])
  193. const funcList : FuncItem[] = [
  194. { iconUrl: '/static/imagesInfo/cx-shop.png', label: '接单时间' },
  195. { iconUrl: '/static/imagesInfo/item-icon.png', label: '服务项目' },
  196. { iconUrl: '/static/imagesInfo/jied-time.png', label: '重选店铺' },
  197. { iconUrl: '/static/imagesInfo/gengxin-wz.png', label: '位置更新' }
  198. ]
  199. const coachData = ref<UTSArray<UTSJSONObject>>([
  200. { value: '456', label: '接单量' },
  201. { value: '10%', label: '加钟率' },
  202. { value: '70%', label: '好评率' },
  203. { value: '3%', label: '复购率' },
  204. { value: '19%', label: '退单率' }
  205. ])
  206. const evalTags = ref<UTSArray<UTSJSONObject>>([
  207. { text: '不良引导', count: 0 },
  208. { text: '手法不好', count: 101 },
  209. { text: '性格温柔', count: 198 },
  210. { text: '服务到位', count: 10 }
  211. ])
  212. const evalList = ref<UTSJSONObject[]>([])
  213. // ==================== 方法 ====================
  214. const toggleOnline = async () => {
  215. state.value.isOnline = !state.value.isOnline
  216. console.log('Status changed:', state.value.isOnline)
  217. const status = state.value.isOnline ? 2 : 1
  218. try {
  219. const response = await editCoachWorkState({ status: status }) as UTSJSONObject
  220. console.log('Set work state result:', response)
  221. const code = response["code"] as number
  222. const message = response["message"] as string
  223. if (code !== 200) {
  224. uni.showToast({ title: message, icon: 'none' })
  225. return false
  226. }
  227. uni.showToast({ title: '状态切换成功', icon: 'success' })
  228. return true
  229. } catch (err : any) {
  230. console.error('设置技师工作状态失败:', err)
  231. uni.showToast({ title: '网络错误', icon: 'none' })
  232. return false
  233. }
  234. }
  235. const httpGetMonthData = async () => {
  236. try {
  237. const response = await getMonthData() as UTSJSONObject
  238. console.log('Month data:', response)
  239. const code = response["code"] as number
  240. const dataObj = response["data"] as UTSJSONObject | null
  241. if (code != 200 || dataObj == null) {
  242. return
  243. }
  244. monthStats.value = [
  245. { label: '本月收益(元)', value: dataObj["commission_amount"] ?? 0 },
  246. { label: '本月接单量(单)', value: dataObj["total_count"] ?? 0 },
  247. {
  248. label: '本月退单率',
  249. value: dataObj["refund_rate"] != ''
  250. ? ((dataObj["refund_rate"] as number) * 100).toFixed(0) + '%'
  251. : '0%'
  252. }
  253. ]
  254. console.log(monthStats.value, 'monthStats.value')
  255. } catch (err : any) {
  256. console.error('获取技师本月数据失败:', err)
  257. }
  258. }
  259. const httpGetAllData = async () => {
  260. try {
  261. const response = await getAllData({}) as UTSJSONObject
  262. console.log('All stats:', response)
  263. const code = response["code"] as number
  264. const dataObj = response["data"] as UTSJSONObject | null
  265. if (code != 200 || dataObj == null) {
  266. return
  267. }
  268. // coachData.value = [
  269. // {
  270. // value: dataObj["receiving"] ?? 0,
  271. // label: '接单量'
  272. // },
  273. // {
  274. // value: ((dataObj["additional"] as UTSJSONObject)?.["rate"] ?? 0) * 100 + '%',
  275. // label: '加钟率'
  276. // },
  277. // {
  278. // value: ((dataObj["comment"] as UTSJSONObject)?.["goodrate"] ?? 0) * 100 + '%',
  279. // label: '好评率'
  280. // },
  281. // {
  282. // value: ((dataObj["renewal"] as UTSJSONObject)?.["rate"] ?? 0) * 100 + '%',
  283. // label: '复购率'
  284. // },
  285. // {
  286. // value: ((dataObj["refund"] as UTSJSONObject)?.["rate"] ?? 0) * 100 + '%',
  287. // label: '退单率'
  288. // }
  289. // ]
  290. } catch (err : any) {
  291. console.error('获取技师统计数据失败:', err)
  292. }
  293. }
  294. const httpGetCoachWorkState = async () => {
  295. try {
  296. const response = await getCoachWorkState() as UTSJSONObject
  297. const code = response["code"] as number
  298. const dataObj = response["data"] as UTSJSONObject | null
  299. if (code != 200 || dataObj == null) {
  300. return
  301. }
  302. // 根据接口返回值修改技师工作状态
  303. // 通常work_status字段:1为在线,2为离线等
  304. state.value.isOnline = (dataObj["work_status"] as number) === 1
  305. } catch (err : any) {
  306. console.error('获取技师工作状态失败:', err)
  307. }
  308. }
  309. // 获取客户评价接口
  310. const httpGetEvaluations = async () => {
  311. try {
  312. const response = await getCommentList({
  313. page: 1,
  314. per_page: 5
  315. }) as UTSJSONObject
  316. const code = response["code"] as number
  317. const data = response["data"] as UTSJSONObject
  318. if (code !== 200) return
  319. evalTags.value = data?.tags_list as UTSArray<UTSJSONObject>;
  320. evalList.value = data?.items as UTSArray<UTSJSONObject>;
  321. } catch (err : any) {
  322. console.error('获取客户评价接口异常', err)
  323. }
  324. }
  325. const httpGetCoachDetail = async () => {
  326. const response = await getCoachDetaile() as UTSJSONObject
  327. // console.log('Coach detail:', response)
  328. const code = response["code"] as number
  329. const dataObj = response["data"] as UTSJSONObject | null
  330. if (code != 200 || dataObj == null) {
  331. return
  332. }
  333. const coach = dataObj["coach"] as UTSJSONObject | null
  334. const coachValue = (coach?.["info_records"] as UTSArray<UTSJSONObject>)[0] as UTSJSONObject | null
  335. // console.log(coachValue, 'coachValue')
  336. // console.log(coachValue?.state_text, 'value');
  337. if (coach == null) {
  338. uni.navigateTo({
  339. url: '/pages/login/merchantRecuitment'
  340. })
  341. return
  342. }
  343. else if (coachValue?.state_text == '审核中' || coachValue?.state_text == '审核拒绝') {
  344. uni.navigateTo({
  345. url: `/pages/login/checkMiddle?stateNum=${coachValue?.state_text == '审核拒绝' ? 3 : 1}&remark=${coachValue?.audit_remark}`
  346. })
  347. }
  348. coachInfo.nickname = dataObj["nickname"] as string
  349. const spaceIndex = (dataObj["created_at"] as string).lastIndexOf(" ")
  350. coachInfo.created_at = (dataObj["created_at"] as string).substring(0, spaceIndex)
  351. // coachInfo.created_at = dataObj["created_at"] as string
  352. coachInfo.avatar = dataObj["avatar"] as string
  353. state.value.isOnline = coach?.["work_status"] == 1 ? true : false as boolean
  354. console.log(coach["work_status"], state.value.isOnline, 'work_status')
  355. httpGetMonthData();
  356. httpGetAllData();
  357. httpGetCoachWorkState();
  358. httpGetEvaluations();
  359. }
  360. const updateLocation = async () => {
  361. // try {
  362. // const location = await new Promise<UniApp.GetLocationSuccess>((resolve, reject) => {
  363. // uni.getLocation({
  364. // type: 'gcj02',
  365. // success: resolve,
  366. // fail: reject
  367. // })
  368. // })
  369. // console.log('Location:', location)
  370. // // 简化处理,实际需要逆地理编码
  371. // userLocation.value = `${location.latitude.toFixed(2)}, ${location.longitude.toFixed(2)}`
  372. // } catch (e) {
  373. // console.error('定位错误:', e)
  374. // uni.showToast({ title: '定位失败', icon: 'none' })
  375. // userLocation.value = '定位失败'
  376. // }
  377. }
  378. const jumpMasterInfo = () => {
  379. uni.navigateTo({
  380. url: '/pages/myEdit/myEdit'
  381. });
  382. }
  383. const jumpSetProject = (label : string) => {
  384. console.log('Navigate to:', label)
  385. switch (label) {
  386. case '接单时间':
  387. uni.navigateTo({ url: '/pages/homepage/setOrderTime' })
  388. break
  389. case '服务项目':
  390. uni.navigateTo({ url: '/pages/homepage/serviceProject' })
  391. break
  392. }
  393. }
  394. const callPolice = () => {
  395. console.log('Emergency call triggered')
  396. }
  397. const jumpStatisics = () => {
  398. uni.navigateTo({ url: '/pages/order/orderStatisics' })
  399. }
  400. const jumpAppraise = () => {
  401. uni.navigateTo({ url: '/pages/order/appraise' })
  402. }
  403. onLoad(() => {
  404. // httpGetCoachDetail()
  405. })
  406. onReady(() => {
  407. httpGetCoachDetail();
  408. })
  409. </script>
  410. <style>
  411. .container {
  412. position: relative;
  413. }
  414. /* 修复9:背景图改为absolute,避免fixed在scroll-view内的问题 */
  415. .bg-image {
  416. position: absolute;
  417. top: 0;
  418. left: 0;
  419. width: 750rpx;
  420. height: 900rpx;
  421. z-index: 0;
  422. }
  423. .page {
  424. padding: 20rpx;
  425. position: relative;
  426. z-index: 1;
  427. }
  428. .city-info {
  429. flex-direction: row;
  430. justify-content: space-between;
  431. align-items: center;
  432. margin-bottom: 16rpx;
  433. }
  434. .city-text-box {
  435. font-size: 28rpx;
  436. color: #333;
  437. }
  438. /* 用户卡片 */
  439. .user-card {
  440. border-radius: 16rpx;
  441. margin-bottom: 32rpx;
  442. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
  443. position: relative;
  444. overflow: hidden;
  445. background-color: #fff;
  446. }
  447. .user-bg {
  448. position: absolute;
  449. top: 0;
  450. left: 0;
  451. width: 100%;
  452. height: 100%;
  453. z-index: 0;
  454. }
  455. .user-content {
  456. flex-direction: row;
  457. justify-content: space-between;
  458. position: relative;
  459. z-index: 1;
  460. }
  461. .user-left {
  462. flex: 1;
  463. flex-direction: column;
  464. }
  465. .user-row {
  466. flex-direction: row;
  467. align-items: center;
  468. margin-bottom: 16rpx;
  469. }
  470. .user-name {
  471. font-size: 40rpx;
  472. font-weight: bold;
  473. color: #333;
  474. }
  475. .tags {
  476. flex-direction: row;
  477. margin-left: 16rpx;
  478. }
  479. .tag-new {
  480. background: linear-gradient(180deg, rgba(207, 221, 62, 0.69) 0%, rgba(162, 184, 29, 1) 100%);
  481. color: #fff;
  482. border-radius: 24rpx;
  483. font-size: 24rpx;
  484. padding: 6rpx 16rpx;
  485. }
  486. .tag {
  487. font-size: 24rpx;
  488. color: #666;
  489. margin-left: 8rpx;
  490. }
  491. .user-role,
  492. .user-shop {
  493. font-size: 26rpx;
  494. color: #999;
  495. margin-left: 8rpx;
  496. margin-right: 24rpx;
  497. }
  498. .online-switch {
  499. margin-top: 24rpx;
  500. }
  501. .user-right {
  502. width: 210rpx;
  503. align-items: center;
  504. }
  505. .time-text {
  506. font-size: 24rpx;
  507. color: #fff;
  508. text-align: center;
  509. margin-bottom: 10rpx;
  510. }
  511. .avatar-img {
  512. width: 138rpx;
  513. height: 138rpx;
  514. border-radius: 69rpx;
  515. border: 4rpx solid #fff;
  516. }
  517. .location-bar {
  518. flex-direction: row;
  519. align-items: center;
  520. background: linear-gradient(to right, rgba(255, 249, 225, 1), rgba(255, 241, 191, 1));
  521. padding: 16rpx 20rpx;
  522. border-radius: 18rpx;
  523. margin: 20rpx;
  524. position: relative;
  525. z-index: 1;
  526. margin-top: 32rpx;
  527. }
  528. .location-text {
  529. flex: 1;
  530. font-size: 26rpx;
  531. color: #333;
  532. margin-left: 8rpx;
  533. }
  534. .location-btn {
  535. font-size: 24rpx;
  536. color: #333;
  537. border: 2rpx solid #333;
  538. padding: 8rpx 16rpx;
  539. border-radius: 16rpx;
  540. }
  541. /* 本月数据 */
  542. .stats-row {
  543. flex-direction: row;
  544. background-color: #fff;
  545. margin-bottom: 32rpx;
  546. border-radius: 24rpx;
  547. padding: 32rpx 0;
  548. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
  549. }
  550. .stat-item {
  551. flex: 1;
  552. align-items: center;
  553. border-right-width: 2rpx;
  554. border-right-color: #eee;
  555. border-right-style: solid;
  556. }
  557. .stat-item:last-child {
  558. border-right-width: 0;
  559. }
  560. .stat-label {
  561. font-size: 24rpx;
  562. color: #999;
  563. margin-bottom: 12rpx;
  564. }
  565. .stat-value {
  566. font-size: 36rpx;
  567. font-weight: bold;
  568. color: #333;
  569. }
  570. /* 功能网格 */
  571. .func-grid {
  572. flex-direction: row;
  573. justify-content: space-around;
  574. background-color: #fff;
  575. margin-bottom: 32rpx;
  576. border-radius: 24rpx;
  577. padding: 32rpx 0;
  578. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
  579. }
  580. .func-item {
  581. align-items: center;
  582. }
  583. .func-icon {
  584. width: 92rpx;
  585. height: 92rpx;
  586. }
  587. .func-label {
  588. font-size: 24rpx;
  589. color: #666;
  590. margin-top: 16rpx;
  591. }
  592. /* 数据统计 */
  593. .data-section,
  594. .eval-section {
  595. background-color: #fff;
  596. margin-bottom: 32rpx;
  597. border-radius: 24rpx;
  598. padding: 32rpx;
  599. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
  600. }
  601. .section-header {
  602. flex-direction: row;
  603. justify-content: space-between;
  604. align-items: center;
  605. margin-bottom: 24rpx;
  606. }
  607. .section-title {
  608. font-size: 32rpx;
  609. font-weight: bold;
  610. color: #333;
  611. }
  612. .section-more {
  613. font-size: 26rpx;
  614. color: #999;
  615. }
  616. .data-grid {
  617. flex-direction: row;
  618. justify-content: space-between;
  619. }
  620. .data-item {
  621. align-items: center;
  622. }
  623. .data-value {
  624. font-size: 32rpx;
  625. font-weight: bold;
  626. color: #333;
  627. margin-bottom: 8rpx;
  628. }
  629. .data-label {
  630. font-size: 24rpx;
  631. color: #999;
  632. }
  633. /* 评价 */
  634. .eval-tags {
  635. flex-direction: row;
  636. margin-bottom: 24rpx;
  637. }
  638. .eval-tag {
  639. font-size: 24rpx;
  640. padding: 8rpx 20rpx;
  641. background-color: #f5f5f5;
  642. border-radius: 24rpx;
  643. margin-right: 16rpx;
  644. color: #666;
  645. }
  646. .eval-item {
  647. flex-direction: row;
  648. }
  649. .eval-avatar {
  650. width: 80rpx;
  651. height: 80rpx;
  652. border-radius: 40rpx;
  653. margin-right: 20rpx;
  654. }
  655. .eval-content {
  656. flex: 1;
  657. flex-direction: column;
  658. }
  659. .eval-top {
  660. flex-direction: row;
  661. justify-content: space-between;
  662. margin-bottom: 8rpx;
  663. }
  664. .eval-name {
  665. font-size: 28rpx;
  666. color: #333;
  667. }
  668. .eval-date {
  669. font-size: 24rpx;
  670. color: #999;
  671. }
  672. .eval-stars {
  673. flex-direction: row;
  674. align-items: center;
  675. margin-bottom: 8rpx;
  676. }
  677. .eval-service {
  678. font-size: 24rpx;
  679. color: #999;
  680. margin-left: 16rpx;
  681. }
  682. .eval-comment {
  683. font-size: 26rpx;
  684. color: #333;
  685. margin-right: 10rpx;
  686. }
  687. </style>