21
This commit is contained in:
parent
a48a4affba
commit
6b60e6fbb4
|
|
@ -21,12 +21,24 @@ public class CreatePlannerRequest
|
|||
[MaxLength(500, ErrorMessage = "头像URL长度不能超过500个字符")]
|
||||
public string Avatar { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 职称
|
||||
/// </summary>
|
||||
[MaxLength(200, ErrorMessage = "职称长度不能超过200个字符")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 简介
|
||||
/// </summary>
|
||||
[MaxLength(1000, ErrorMessage = "简介长度不能超过1000个字符")]
|
||||
public string? Introduction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标签(逗号分隔)
|
||||
/// </summary>
|
||||
[MaxLength(500, ErrorMessage = "标签长度不能超过500个字符")]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 咨询价格
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -20,11 +20,21 @@ public class PlannerDto
|
|||
/// </summary>
|
||||
public string Avatar { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 职称
|
||||
/// </summary>
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 简介
|
||||
/// </summary>
|
||||
public string? Introduction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标签(逗号分隔)
|
||||
/// </summary>
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 咨询价格
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -27,12 +27,24 @@ public class UpdatePlannerRequest
|
|||
[MaxLength(500, ErrorMessage = "头像URL长度不能超过500个字符")]
|
||||
public string Avatar { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 职称
|
||||
/// </summary>
|
||||
[MaxLength(200, ErrorMessage = "职称长度不能超过200个字符")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 简介
|
||||
/// </summary>
|
||||
[MaxLength(1000, ErrorMessage = "简介长度不能超过1000个字符")]
|
||||
public string? Introduction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标签(逗号分隔)
|
||||
/// </summary>
|
||||
[MaxLength(500, ErrorMessage = "标签长度不能超过500个字符")]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 咨询价格
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -144,7 +144,9 @@ public class PlannerService : IPlannerService
|
|||
Id = p.Id,
|
||||
Name = p.Name,
|
||||
Avatar = p.Avatar,
|
||||
Title = p.Title,
|
||||
Introduction = p.Introduction,
|
||||
Tags = p.Tags,
|
||||
Price = p.Price,
|
||||
Sort = p.Sort,
|
||||
Status = p.Status,
|
||||
|
|
@ -171,7 +173,9 @@ public class PlannerService : IPlannerService
|
|||
{
|
||||
Name = request.Name,
|
||||
Avatar = request.Avatar,
|
||||
Title = request.Title,
|
||||
Introduction = request.Introduction,
|
||||
Tags = request.Tags,
|
||||
Price = request.Price,
|
||||
Sort = request.Sort,
|
||||
Status = request.Status,
|
||||
|
|
@ -209,7 +213,9 @@ public class PlannerService : IPlannerService
|
|||
|
||||
planner.Name = request.Name;
|
||||
planner.Avatar = request.Avatar;
|
||||
planner.Title = request.Title;
|
||||
planner.Introduction = request.Introduction;
|
||||
planner.Tags = request.Tags;
|
||||
planner.Price = request.Price;
|
||||
planner.Sort = request.Sort;
|
||||
planner.Status = request.Status;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ public class PlannerService : IPlannerService
|
|||
Id = p.Id,
|
||||
Name = p.Name,
|
||||
Avatar = p.Avatar,
|
||||
Title = p.Title,
|
||||
Introduction = p.Introduction,
|
||||
Tags = p.Tags,
|
||||
Price = p.Price
|
||||
})
|
||||
.ToListAsync();
|
||||
|
|
|
|||
|
|
@ -30,12 +30,24 @@ public class Planner
|
|||
[MaxLength(500)]
|
||||
public string Avatar { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 职称
|
||||
/// </summary>
|
||||
[MaxLength(200)]
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 简介
|
||||
/// </summary>
|
||||
[MaxLength(1000)]
|
||||
public string? Introduction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标签(逗号分隔)
|
||||
/// </summary>
|
||||
[MaxLength(500)]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 咨询价格
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -20,11 +20,21 @@ public class PlannerDto
|
|||
/// </summary>
|
||||
public string Avatar { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 职称
|
||||
/// </summary>
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 简介
|
||||
/// </summary>
|
||||
public string? Introduction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标签(逗号分隔)
|
||||
/// </summary>
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 价格
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -57,9 +57,9 @@
|
|||
@click="handleNavigationClick(item)"
|
||||
>
|
||||
<!-- 即将上线标签 -->
|
||||
<view v-if="item.status === 2" class="coming-soon-tag">
|
||||
<!-- <view v-if="item.status === 2" class="coming-soon-tag">
|
||||
<text>即将上线</text>
|
||||
</view>
|
||||
</view> -->
|
||||
<image
|
||||
:src="item.imageUrl"
|
||||
mode="aspectFit"
|
||||
|
|
@ -225,7 +225,7 @@ function handleNavigationClick(item) {
|
|||
// 即将上线的导航,弹出提示
|
||||
if (item.status === 2) {
|
||||
uni.showToast({
|
||||
title: '该功能暂未开放',
|
||||
title: '该功能即将上线',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
|
|
|
|||
|
|
@ -5,12 +5,14 @@
|
|||
|
||||
<!-- 页面内容 -->
|
||||
<view class="page-content">
|
||||
<!-- 提示文字 -->
|
||||
<view class="page-tip">点击选择您喜欢的规划师</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<Loading v-if="pageLoading" type="page" :loading="true" />
|
||||
|
||||
<!-- 规划师列表 -->
|
||||
<view v-else class="planner-list">
|
||||
<!-- 有数据时显示列表 -->
|
||||
<template v-if="plannerList.length > 0">
|
||||
<view
|
||||
class="planner-card"
|
||||
|
|
@ -18,7 +20,9 @@
|
|||
:key="item.id || index"
|
||||
@click="handlePlannerClick(item)"
|
||||
>
|
||||
<!-- 规划师头像 -->
|
||||
<!-- 上半部分:头像 + 姓名职称 + 标签 -->
|
||||
<view class="card-top">
|
||||
<!-- 头像 -->
|
||||
<view class="planner-avatar">
|
||||
<image
|
||||
:src="item.avatar || item.photo || '/static/ic_empty.png'"
|
||||
|
|
@ -28,36 +32,46 @@
|
|||
/>
|
||||
</view>
|
||||
|
||||
<!-- 规划师信息 -->
|
||||
<!-- 右侧信息 -->
|
||||
<view class="planner-info">
|
||||
<!-- 姓名 -->
|
||||
<view class="planner-name">{{ item.name || '规划师' }}</view>
|
||||
<!-- 姓名 | 职称 -->
|
||||
<view class="planner-name-row">
|
||||
<text class="planner-name">{{ item.name || '规划师' }}</text>
|
||||
<text v-if="item.title" class="planner-title">|{{ item.title }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 介绍 -->
|
||||
<view class="planner-intro">{{ item.intro || item.introduction || '暂无介绍' }}</view>
|
||||
<!-- 标签列表 -->
|
||||
<view class="planner-tags" v-if="parseTags(item.tags).length > 0">
|
||||
<view
|
||||
class="tag-item"
|
||||
v-for="(tag, tagIndex) in parseTags(item.tags)"
|
||||
:key="tagIndex"
|
||||
>
|
||||
{{ tag }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 价格 -->
|
||||
<!-- 无标签时显示简介 -->
|
||||
<view class="planner-intro" v-else-if="item.introduction">
|
||||
{{ item.introduction }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 下半部分:价格 + 按钮 -->
|
||||
<view class="card-bottom">
|
||||
<view class="planner-price">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price-value">{{ formatPrice(item.price) }}</text>
|
||||
<text class="price-unit">/次</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 预约按钮 -->
|
||||
<view class="planner-action">
|
||||
<view class="book-btn">预约</view>
|
||||
<view class="select-btn">点击选择</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 无数据时显示空状态 -->
|
||||
<!-- 空状态 -->
|
||||
<view v-else class="empty-state">
|
||||
<image
|
||||
src="/static/ic_empty.png"
|
||||
mode="aspectFit"
|
||||
class="empty-icon"
|
||||
/>
|
||||
<image src="/static/ic_empty.png" mode="aspectFit" class="empty-icon" />
|
||||
<text class="empty-text">暂无规划师</text>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -71,7 +85,7 @@
|
|||
<script setup>
|
||||
/**
|
||||
* 规划师列表页面
|
||||
* 展示规划师卡片:照片、姓名、介绍、价格
|
||||
* 展示规划师卡片:照片、姓名、职称、标签、价格
|
||||
*/
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onPullDownRefresh } from '@dcloudio/uni-app'
|
||||
|
|
@ -91,7 +105,6 @@ async function loadPlannerList() {
|
|||
try {
|
||||
const res = await getPlannerList()
|
||||
if (res && res.code === 0 && res.data) {
|
||||
// 支持多种数据格式
|
||||
if (Array.isArray(res.data)) {
|
||||
plannerList.value = res.data
|
||||
} else if (res.data.list && Array.isArray(res.data.list)) {
|
||||
|
|
@ -102,27 +115,32 @@ async function loadPlannerList() {
|
|||
}
|
||||
} catch (error) {
|
||||
console.error('加载规划师列表失败:', error)
|
||||
uni.showToast({
|
||||
title: '加载失败,请稍后重试',
|
||||
icon: 'none'
|
||||
})
|
||||
uni.showToast({ title: '加载失败,请稍后重试', icon: 'none' })
|
||||
} finally {
|
||||
pageLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析标签字符串为数组
|
||||
* @param {string} tags - 逗号分隔的标签字符串
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function parseTags(tags) {
|
||||
if (!tags) return []
|
||||
return tags.split(',').map(t => t.trim()).filter(Boolean)
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化价格
|
||||
* @param {number|string} price - 价格
|
||||
* @returns {string} 格式化后的价格
|
||||
* @returns {string}
|
||||
*/
|
||||
function formatPrice(price) {
|
||||
if (price === undefined || price === null) return '0'
|
||||
const num = Number(price)
|
||||
if (isNaN(num)) return '0'
|
||||
// 如果是整数,不显示小数点
|
||||
if (Number.isInteger(num)) return num.toString()
|
||||
// 否则保留两位小数
|
||||
return num.toFixed(2)
|
||||
}
|
||||
|
||||
|
|
@ -134,10 +152,9 @@ function handleAvatarError(index) {
|
|||
}
|
||||
|
||||
/**
|
||||
* 处理规划师点击
|
||||
* 处理规划师点击 - 跳转到预约页面
|
||||
*/
|
||||
function handlePlannerClick(item) {
|
||||
// 跳转到预约页面
|
||||
uni.navigateTo({
|
||||
url: `/pages/planner/book/index?plannerId=${item.id}&plannerName=${encodeURIComponent(item.name || '')}`
|
||||
})
|
||||
|
|
@ -162,43 +179,61 @@ onMounted(() => {
|
|||
<style lang="scss" scoped>
|
||||
@import '@/styles/variables.scss';
|
||||
|
||||
// 橙色主题色
|
||||
$orange-color: #E8740E;
|
||||
$orange-light: #FFF8F0;
|
||||
$orange-gradient-start: #FFF5EB;
|
||||
$orange-gradient-end: #FFFFFF;
|
||||
|
||||
.planner-list-page {
|
||||
min-height: 100vh;
|
||||
background-color: $bg-color;
|
||||
}
|
||||
|
||||
// 页面内容
|
||||
.page-content {
|
||||
padding: $spacing-lg;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
// 顶部提示文字
|
||||
.page-tip {
|
||||
text-align: center;
|
||||
font-size: $font-size-md;
|
||||
color: $text-secondary;
|
||||
margin-bottom: $spacing-lg;
|
||||
}
|
||||
|
||||
// 规划师列表
|
||||
.planner-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-md;
|
||||
gap: $spacing-lg;
|
||||
}
|
||||
|
||||
// 规划师卡片
|
||||
// 规划师卡片 - 橙色渐变背景
|
||||
.planner-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: $bg-white;
|
||||
border-radius: $border-radius-lg;
|
||||
background: linear-gradient(135deg, $orange-gradient-start 0%, $orange-gradient-end 60%);
|
||||
border-radius: $border-radius-xl;
|
||||
padding: $spacing-lg;
|
||||
box-shadow: $shadow-sm;
|
||||
border-left: 6rpx solid $orange-color;
|
||||
|
||||
&:active {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
// 规划师头像
|
||||
// 上半部分:头像 + 信息
|
||||
.card-top {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
// 头像
|
||||
.planner-avatar {
|
||||
flex-shrink: 0;
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
height: 180rpx;
|
||||
border-radius: $border-radius-md;
|
||||
overflow: hidden;
|
||||
margin-right: $spacing-md;
|
||||
|
|
@ -209,26 +244,52 @@ onMounted(() => {
|
|||
}
|
||||
}
|
||||
|
||||
// 规划师信息
|
||||
// 右侧信息区
|
||||
.planner-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
// 姓名 + 职称行
|
||||
.planner-name-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
.planner-name {
|
||||
font-size: $font-size-xl;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
.planner-title {
|
||||
font-size: $font-size-sm;
|
||||
color: $text-secondary;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
// 标签列表
|
||||
.planner-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: $spacing-xs;
|
||||
}
|
||||
|
||||
// 规划师姓名
|
||||
.planner-name {
|
||||
font-size: $font-size-lg;
|
||||
font-weight: $font-weight-medium;
|
||||
color: $text-color;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
.tag-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6rpx 16rpx;
|
||||
font-size: $font-size-xs;
|
||||
color: $orange-color;
|
||||
background-color: rgba(232, 116, 14, 0.08);
|
||||
border: 1rpx solid rgba(232, 116, 14, 0.2);
|
||||
border-radius: $border-radius-sm;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
// 规划师介绍
|
||||
// 简介(无标签时的备选显示)
|
||||
.planner-intro {
|
||||
font-size: $font-size-sm;
|
||||
color: $text-secondary;
|
||||
|
|
@ -239,52 +300,47 @@ onMounted(() => {
|
|||
line-height: 1.5;
|
||||
}
|
||||
|
||||
// 规划师价格
|
||||
// 下半部分:价格 + 按钮
|
||||
.card-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: $spacing-md;
|
||||
}
|
||||
|
||||
// 价格
|
||||
.planner-price {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-top: $spacing-xs;
|
||||
|
||||
.price-symbol {
|
||||
font-size: $font-size-sm;
|
||||
color: $error-color;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: $font-size-lg;
|
||||
color: $orange-color;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
|
||||
.price-value {
|
||||
font-size: $font-size-xl;
|
||||
color: $error-color;
|
||||
font-size: 44rpx;
|
||||
color: $orange-color;
|
||||
font-weight: $font-weight-bold;
|
||||
margin-left: 2rpx;
|
||||
}
|
||||
|
||||
.price-unit {
|
||||
font-size: $font-size-xs;
|
||||
color: $text-placeholder;
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 预约按钮区域
|
||||
.planner-action {
|
||||
flex-shrink: 0;
|
||||
margin-left: $spacing-md;
|
||||
|
||||
.book-btn {
|
||||
// 点击选择按钮
|
||||
.select-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 120rpx;
|
||||
height: 64rpx;
|
||||
background-color: $primary-color;
|
||||
padding: 16rpx 48rpx;
|
||||
background-color: $orange-color;
|
||||
color: $text-white;
|
||||
font-size: $font-size-md;
|
||||
font-weight: $font-weight-medium;
|
||||
border-radius: $border-radius-round;
|
||||
|
||||
&:active {
|
||||
background-color: $primary-dark;
|
||||
}
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user