feat: 新增订单列表交互
This commit is contained in:
BIN
pages/order/components/OrderCard/images/service.png
Normal file
BIN
pages/order/components/OrderCard/images/service.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
100
pages/order/components/OrderCard/index.vue
Normal file
100
pages/order/components/OrderCard/index.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<view class="order-card" @click="handleCardClick">
|
||||
<!-- 卡片头部 -->
|
||||
<view class="card-header">
|
||||
<view class="status-info">
|
||||
<image class="status-icon" src="./images/service.png"></image>
|
||||
<view class="order-title">{{ orderData.title }}</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="orderData.status !== 'pending'"
|
||||
:class="['status-tag', `tag-${orderData.status}`]"
|
||||
>
|
||||
{{ getStatusText(orderData.status) }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<Divider />
|
||||
|
||||
<!-- 卡片内容 -->
|
||||
<view class="card-content">
|
||||
<view class="info-row">
|
||||
<text class="label">创建时间:</text>
|
||||
<text class="value">{{ orderData.createTime }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">联系房客:</text>
|
||||
<text class="value">{{ orderData.contactName }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">联系电话:</text>
|
||||
<text class="value">{{ orderData.contactPhone }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作区域 -->
|
||||
<view v-if="orderData.status === 'pending'" class="action-area">
|
||||
<button class="action-btn" @click.stop="handleCall">立即呼叫</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Divider from "@/components/Divider/index.vue";
|
||||
import { defineProps } from "vue";
|
||||
|
||||
// Props
|
||||
const props = defineProps({
|
||||
orderData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({
|
||||
id: "",
|
||||
title: "",
|
||||
createTime: "",
|
||||
contactName: "",
|
||||
contactPhone: "",
|
||||
status: "pending", // pending-待处理, completed-已完成, cancelled-已取消
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(["click", "call", "complete"]);
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
pending: "待处理",
|
||||
completed: "已完成",
|
||||
cancelled: "已取消",
|
||||
processing: "处理中",
|
||||
};
|
||||
return statusMap[status] || "未知状态";
|
||||
};
|
||||
|
||||
// 处理卡片点击
|
||||
const handleCardClick = () => {
|
||||
emit("click", props.orderData);
|
||||
};
|
||||
|
||||
// 处理呼叫
|
||||
const handleCall = () => {
|
||||
emit("call", props.orderData);
|
||||
};
|
||||
|
||||
// 处理完成
|
||||
const handleComplete = () => {
|
||||
emit("complete", props.orderData);
|
||||
};
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
getStatusText,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
170
pages/order/components/OrderCard/prompt.md
Normal file
170
pages/order/components/OrderCard/prompt.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# OrderCard 工单卡片组件
|
||||
|
||||
## 组件概述
|
||||
|
||||
OrderCard 是一个用于显示工单信息的卡片组件,支持多种工单状态展示、操作按钮和自定义内容。适用于工单管理、客服系统等场景。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- ✅ 多种工单状态支持(待处理、处理中、已完成、已取消)
|
||||
- ✅ 状态图标和标签显示
|
||||
- ✅ 工单基本信息展示
|
||||
- ✅ 可配置的操作按钮
|
||||
- ✅ 自定义操作区域插槽
|
||||
- ✅ 点击事件和操作事件
|
||||
- ✅ 响应式设计
|
||||
- ✅ 暗色模式支持
|
||||
- ✅ 优雅的交互动画
|
||||
|
||||
## 组件属性 (Props)
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 必填 | 说明 |
|
||||
|--------|------|--------|------|------|
|
||||
| orderData | Object | - | 是 | 工单数据对象 |
|
||||
| showActions | Boolean | true | 否 | 是否显示操作按钮区域 |
|
||||
|
||||
### orderData 对象结构
|
||||
|
||||
```javascript
|
||||
{
|
||||
id: String, // 工单ID
|
||||
title: String, // 工单标题
|
||||
createTime: String, // 创建时间
|
||||
contactName: String, // 联系人姓名
|
||||
contactPhone: String, // 联系电话
|
||||
status: String // 工单状态:pending/processing/completed/cancelled
|
||||
}
|
||||
```
|
||||
|
||||
## 组件事件 (Events)
|
||||
|
||||
| 事件名 | 参数 | 说明 |
|
||||
|--------|------|------|
|
||||
| click | orderData | 卡片点击事件 |
|
||||
| call | orderData | 呼叫按钮点击事件 |
|
||||
| complete | orderData | 完成按钮点击事件 |
|
||||
|
||||
## 插槽 (Slots)
|
||||
|
||||
| 插槽名 | 说明 |
|
||||
|--------|------|
|
||||
| actions | 自定义操作按钮区域 |
|
||||
|
||||
## 工单状态说明
|
||||
|
||||
| 状态值 | 显示文本 | 图标颜色 | 标签样式 |
|
||||
|--------|----------|----------|----------|
|
||||
| pending | 待处理 | 橙色 | 橙色边框 |
|
||||
| processing | 处理中 | 蓝色 | 蓝色边框 |
|
||||
| completed | 已完成 | 绿色 | 绿色边框 |
|
||||
| cancelled | 已取消 | 灰色 | 灰色边框 |
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 基础用法
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<OrderCard
|
||||
:orderData="orderInfo"
|
||||
@click="handleCardClick"
|
||||
@call="handleCall"
|
||||
@complete="handleComplete"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import OrderCard from '@/components/OrderCard/index.vue'
|
||||
|
||||
const orderInfo = {
|
||||
id: '001',
|
||||
title: '空调不制冷,需要维修',
|
||||
createTime: '2024-01-15 14:30',
|
||||
contactName: '张先生',
|
||||
contactPhone: '138****8888',
|
||||
status: 'pending'
|
||||
}
|
||||
|
||||
const handleCardClick = (orderData) => {
|
||||
console.log('卡片点击', orderData)
|
||||
}
|
||||
|
||||
const handleCall = (orderData) => {
|
||||
console.log('呼叫', orderData.contactPhone)
|
||||
}
|
||||
|
||||
const handleComplete = (orderData) => {
|
||||
console.log('标记完成', orderData.id)
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 隐藏操作按钮
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<OrderCard
|
||||
:orderData="completedOrder"
|
||||
:showActions="false"
|
||||
@click="handleCardClick"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 自定义操作按钮
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<OrderCard
|
||||
:orderData="orderInfo"
|
||||
@click="handleCardClick"
|
||||
>
|
||||
<template #actions>
|
||||
<button class="custom-btn" @click.stop="handleEdit">
|
||||
编辑
|
||||
</button>
|
||||
<button class="custom-btn" @click.stop="handleDelete">
|
||||
删除
|
||||
</button>
|
||||
</template>
|
||||
</OrderCard>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 样式定制
|
||||
|
||||
组件支持通过 CSS 变量进行样式定制:
|
||||
|
||||
```css
|
||||
.order-card {
|
||||
--card-bg: #ffffff;
|
||||
--card-radius: 12px;
|
||||
--card-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
--primary-color: #007AFF;
|
||||
--success-color: #52C41A;
|
||||
--warning-color: #FF8C00;
|
||||
--danger-color: #FF3B30;
|
||||
}
|
||||
```
|
||||
|
||||
## 响应式支持
|
||||
|
||||
- 在小屏设备(≤375px)上自动调整字体大小和间距
|
||||
- 支持暗色模式自动适配
|
||||
- 触摸设备优化的交互体验
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **数据格式**:确保传入的 `orderData` 包含所有必需字段
|
||||
2. **状态值**:`status` 字段必须是预定义的状态值之一
|
||||
3. **事件处理**:使用 `@click.stop` 防止操作按钮事件冒泡
|
||||
4. **性能优化**:大量卡片时建议使用虚拟滚动
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.0 (2024-01-15)
|
||||
- 初始版本发布
|
||||
- 支持基础工单信息展示
|
||||
- 支持多种状态和操作按钮
|
||||
- 支持自定义插槽
|
||||
- 响应式设计和暗色模式支持
|
||||
130
pages/order/components/OrderCard/styles/index.scss
Normal file
130
pages/order/components/OrderCard/styles/index.scss
Normal file
@@ -0,0 +1,130 @@
|
||||
.order-card {
|
||||
background-color: #fff;
|
||||
border-radius: 6px 6px 12px 12px;
|
||||
box-shadow: 0px 3px 8px 0 rgba(0,0,0,0.12);
|
||||
margin: 12px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&.expired {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 14px 14px 12px 16px;
|
||||
}
|
||||
|
||||
.status-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.order-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
line-height: 1.4;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
box-sizing: border-box;
|
||||
padding: 6px 16px;
|
||||
border-radius: 20px ;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.tag-pending {
|
||||
background-color: #FFF7E6;
|
||||
color: #FF8C00;
|
||||
border: 1px solid #FFD591;
|
||||
}
|
||||
|
||||
&.tag-completed {
|
||||
background-color: #F6FFED;
|
||||
color: #52C41A;
|
||||
border: 1px solid #B7EB8F;
|
||||
}
|
||||
|
||||
&.tag-cancelled {
|
||||
background-color: #F5F5F5;
|
||||
color: #999999;
|
||||
border: 1px solid #D9D9D9;
|
||||
}
|
||||
|
||||
&.tag-processing {
|
||||
background-color: #E6F7FF;
|
||||
color: #1890FF;
|
||||
border: 1px solid #91D5FF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.card-content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 12px;
|
||||
color: #666666;
|
||||
flex-shrink: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.action-area {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width: 280px;
|
||||
height: 42px;
|
||||
border-radius: 50px;
|
||||
border: 2px solid #FFCA70;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
background: linear-gradient( 179deg, #FFB100 0%, #FF7F19 100%);
|
||||
color: #ffffff;
|
||||
margin: 0 auto;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #FF7A00 0%, #FF6600 100%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user