Claw 项目完整结构提交
This commit is contained in:
309
Claw/client/wechat_app/pages/task/task.js
Normal file
309
Claw/client/wechat_app/pages/task/task.js
Normal file
@@ -0,0 +1,309 @@
|
||||
// 任务页面逻辑
|
||||
const { API, util, constants } = require('../../utils/api.js')
|
||||
const { TASK_STATUS, TASK_TYPE } = constants
|
||||
|
||||
Page({
|
||||
data: {
|
||||
taskTitle: '',
|
||||
taskDescription: '',
|
||||
taskTypeIndex: 0,
|
||||
priorityIndex: 0,
|
||||
tasks: [],
|
||||
filteredTasks: [],
|
||||
filterStatus: 'all',
|
||||
canSubmit: false,
|
||||
|
||||
taskTypes: [
|
||||
{ name: '文本处理', value: 'text' },
|
||||
{ name: '图像识别', value: 'image' },
|
||||
{ name: '文件分析', value: 'file' },
|
||||
{ name: '数据查询', value: 'data' },
|
||||
{ name: '其他', value: 'other' }
|
||||
],
|
||||
|
||||
priorities: [
|
||||
{ name: '低', value: 'low' },
|
||||
{ name: '中', value: 'medium' },
|
||||
{ name: '高', value: 'high' },
|
||||
{ name: '紧急', value: 'urgent' }
|
||||
]
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadTasks()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.loadTasks()
|
||||
},
|
||||
|
||||
// 监听输入变化
|
||||
observers: {
|
||||
'taskTitle, taskDescription': function(title, description) {
|
||||
this.setData({
|
||||
canSubmit: title.trim().length > 0 && description.trim().length > 0
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 标题输入
|
||||
onTitleInput(e) {
|
||||
this.setData({
|
||||
taskTitle: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
// 描述输入
|
||||
onDescriptionInput(e) {
|
||||
this.setData({
|
||||
taskDescription: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
// 类型选择
|
||||
onTypeChange(e) {
|
||||
this.setData({
|
||||
taskTypeIndex: parseInt(e.detail.value)
|
||||
})
|
||||
},
|
||||
|
||||
// 优先级选择
|
||||
onPriorityChange(e) {
|
||||
this.setData({
|
||||
priorityIndex: parseInt(e.detail.value)
|
||||
})
|
||||
},
|
||||
|
||||
// 提交任务
|
||||
async submitTask() {
|
||||
if (!this.data.canSubmit) {
|
||||
return
|
||||
}
|
||||
|
||||
util.showLoading('提交中...')
|
||||
|
||||
try {
|
||||
const taskData = {
|
||||
title: this.data.taskTitle.trim(),
|
||||
description: this.data.taskDescription.trim(),
|
||||
type: this.data.taskTypes[this.data.taskTypeIndex].value,
|
||||
priority: this.data.priorities[this.data.priorityIndex].value,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
|
||||
const result = await API.submitTask(taskData)
|
||||
|
||||
util.hideLoading()
|
||||
|
||||
if (result.success) {
|
||||
util.showSuccess('任务提交成功')
|
||||
|
||||
// 清空表单
|
||||
this.setData({
|
||||
taskTitle: '',
|
||||
taskDescription: '',
|
||||
taskTypeIndex: 0,
|
||||
priorityIndex: 0
|
||||
})
|
||||
|
||||
// 重新加载任务列表
|
||||
this.loadTasks()
|
||||
|
||||
// 滚动到顶部
|
||||
wx.pageScrollTo({
|
||||
scrollTop: 0,
|
||||
duration: 300
|
||||
})
|
||||
} else {
|
||||
util.showError(result.message || '任务提交失败')
|
||||
}
|
||||
} catch (error) {
|
||||
util.hideLoading()
|
||||
console.error('提交任务失败:', error)
|
||||
util.showError('提交失败,请重试')
|
||||
}
|
||||
},
|
||||
|
||||
// 加载任务列表
|
||||
async loadTasks() {
|
||||
try {
|
||||
const result = await API.getTaskList(1, 50)
|
||||
|
||||
if (result.success && result.data) {
|
||||
const tasks = result.data.tasks.map(task => ({
|
||||
id: task.id,
|
||||
title: task.title,
|
||||
description: task.description,
|
||||
type: task.type,
|
||||
status: task.status,
|
||||
priority: task.priority,
|
||||
createdAt: util.formatRelativeTime(new Date(task.createdAt)),
|
||||
updatedAt: task.updatedAt ? util.formatRelativeTime(new Date(task.updatedAt)) : '',
|
||||
result: task.result || '',
|
||||
progress: task.progress || 0
|
||||
}))
|
||||
|
||||
this.setData({
|
||||
tasks: tasks
|
||||
})
|
||||
|
||||
this.filterTasks()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载任务列表失败:', error)
|
||||
util.showError('加载失败')
|
||||
}
|
||||
},
|
||||
|
||||
// 设置过滤器
|
||||
setFilter(e) {
|
||||
const status = e.currentTarget.dataset.status
|
||||
this.setData({
|
||||
filterStatus: status
|
||||
})
|
||||
this.filterTasks()
|
||||
},
|
||||
|
||||
// 过滤任务
|
||||
filterTasks() {
|
||||
const { tasks, filterStatus } = this.data
|
||||
|
||||
if (filterStatus === 'all') {
|
||||
this.setData({
|
||||
filteredTasks: tasks
|
||||
})
|
||||
} else {
|
||||
const filtered = tasks.filter(task => task.status === filterStatus)
|
||||
this.setData({
|
||||
filteredTasks: filtered
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 开始任务
|
||||
async onStartTask(e) {
|
||||
const { taskId, title } = e.detail
|
||||
|
||||
try {
|
||||
const confirmed = await util.showModal('确认开始', `确定要开始处理任务"${title}"吗?`)
|
||||
|
||||
if (confirmed) {
|
||||
util.showLoading('处理中...')
|
||||
|
||||
// 这里可以调用开始任务的API
|
||||
// await API.startTask(taskId)
|
||||
|
||||
util.hideLoading()
|
||||
util.showSuccess('任务已开始')
|
||||
|
||||
// 重新加载任务列表
|
||||
this.loadTasks()
|
||||
}
|
||||
} catch (error) {
|
||||
util.hideLoading()
|
||||
console.error('开始任务失败:', error)
|
||||
util.showError('操作失败')
|
||||
}
|
||||
},
|
||||
|
||||
// 完成任务
|
||||
async onCompleteTask(e) {
|
||||
const { taskId, title } = e.detail
|
||||
|
||||
try {
|
||||
const confirmed = await util.showModal('确认完成', `确定要标记任务"${title}"为已完成吗?`)
|
||||
|
||||
if (confirmed) {
|
||||
util.showLoading('处理中...')
|
||||
|
||||
// 这里可以调用完成任务的API
|
||||
// await API.completeTask(taskId)
|
||||
|
||||
util.hideLoading()
|
||||
util.showSuccess('任务已完成')
|
||||
|
||||
// 重新加载任务列表
|
||||
this.loadTasks()
|
||||
}
|
||||
} catch (error) {
|
||||
util.hideLoading()
|
||||
console.error('完成任务失败:', error)
|
||||
util.showError('操作失败')
|
||||
}
|
||||
},
|
||||
|
||||
// 重试任务
|
||||
async onRetryTask(e) {
|
||||
const { taskId, title } = e.detail
|
||||
|
||||
try {
|
||||
const confirmed = await util.showModal('确认重试', `确定要重试任务"${title}"吗?`)
|
||||
|
||||
if (confirmed) {
|
||||
util.showLoading('处理中...')
|
||||
|
||||
// 这里可以调用重试任务的API
|
||||
// await API.retryTask(taskId)
|
||||
|
||||
util.hideLoading()
|
||||
util.showSuccess('任务已重试')
|
||||
|
||||
// 重新加载任务列表
|
||||
this.loadTasks()
|
||||
}
|
||||
} catch (error) {
|
||||
util.hideLoading()
|
||||
console.error('重试任务失败:', error)
|
||||
util.showError('操作失败')
|
||||
}
|
||||
},
|
||||
|
||||
// 取消任务
|
||||
async onCancelTask(e) {
|
||||
const { taskId, title } = e.detail
|
||||
|
||||
try {
|
||||
const confirmed = await util.showModal('确认取消', `确定要取消任务"${title}"吗?`)
|
||||
|
||||
if (confirmed) {
|
||||
util.showLoading('处理中...')
|
||||
|
||||
// 这里可以调用取消任务的API
|
||||
// await API.cancelTask(taskId)
|
||||
|
||||
util.hideLoading()
|
||||
util.showSuccess('任务已取消')
|
||||
|
||||
// 重新加载任务列表
|
||||
this.loadTasks()
|
||||
}
|
||||
} catch (error) {
|
||||
util.hideLoading()
|
||||
console.error('取消任务失败:', error)
|
||||
util.showError('操作失败')
|
||||
}
|
||||
},
|
||||
|
||||
// 查看任务详情
|
||||
onTaskDetail(e) {
|
||||
const { taskId, title, description, status, result, createdAt, updatedAt } = e.detail
|
||||
|
||||
wx.navigateTo({
|
||||
url: `/pages/task-detail/task-detail?taskId=${taskId}&title=${encodeURIComponent(title)}&description=${encodeURIComponent(description)}&status=${status}&result=${encodeURIComponent(result)}&createdAt=${encodeURIComponent(createdAt)}&updatedAt=${encodeURIComponent(updatedAt)}`
|
||||
})
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
async onPullDownRefresh() {
|
||||
await this.loadTasks()
|
||||
wx.stopPullDownRefresh()
|
||||
},
|
||||
|
||||
// 分享
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '智控未来 - 任务管理',
|
||||
path: '/pages/task/task'
|
||||
}
|
||||
}
|
||||
})
|
||||
4
Claw/client/wechat_app/pages/task/task.json
Normal file
4
Claw/client/wechat_app/pages/task/task.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "任务管理",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
128
Claw/client/wechat_app/pages/task/task.wxml
Normal file
128
Claw/client/wechat_app/pages/task/task.wxml
Normal file
@@ -0,0 +1,128 @@
|
||||
<!-- 任务页面 -->
|
||||
<view class="task-container">
|
||||
<!-- 任务创建区域 -->
|
||||
<view class="task-create">
|
||||
<view class="input-group">
|
||||
<text class="label">任务标题:</text>
|
||||
<input
|
||||
class="task-input"
|
||||
placeholder="请输入任务标题"
|
||||
value="{{taskTitle}}"
|
||||
bindinput="onTitleInput"
|
||||
maxlength="100"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="input-group">
|
||||
<text class="label">任务描述:</text>
|
||||
<textarea
|
||||
class="task-textarea"
|
||||
placeholder="请输入任务描述"
|
||||
value="{{taskDescription}}"
|
||||
bindinput="onDescriptionInput"
|
||||
maxlength="500"
|
||||
auto-height
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="input-group">
|
||||
<text class="label">任务类型:</text>
|
||||
<picker
|
||||
bindchange="onTypeChange"
|
||||
value="{{taskTypeIndex}}"
|
||||
range="{{taskTypes}}"
|
||||
range-key="{{'name'}}"
|
||||
>
|
||||
<view class="picker">
|
||||
{{taskTypes[taskTypeIndex].name}}
|
||||
<text class="picker-arrow">▼</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="input-group">
|
||||
<text class="label">优先级:</text>
|
||||
<picker
|
||||
bindchange="onPriorityChange"
|
||||
value="{{priorityIndex}}"
|
||||
range="{{priorities}}"
|
||||
range-key="{{'name'}}"
|
||||
>
|
||||
<view class="picker">
|
||||
{{priorities[priorityIndex].name}}
|
||||
<text class="picker-arrow">▼</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<button class="submit-btn" bindtap="submitTask" disabled="{{!canSubmit}}">
|
||||
提交任务
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 任务列表 -->
|
||||
<view class="task-list">
|
||||
<view class="list-header">
|
||||
<text class="list-title">任务列表</text>
|
||||
<view class="filter-buttons">
|
||||
<button
|
||||
class="filter-btn {{filterStatus === 'all' ? 'active' : ''}}"
|
||||
bindtap="setFilter"
|
||||
data-status="all"
|
||||
>
|
||||
全部
|
||||
</button>
|
||||
<button
|
||||
class="filter-btn {{filterStatus === 'pending' ? 'active' : ''}}"
|
||||
bindtap="setFilter"
|
||||
data-status="pending"
|
||||
>
|
||||
待处理
|
||||
</button>
|
||||
<button
|
||||
class="filter-btn {{filterStatus === 'processing' ? 'active' : ''}}"
|
||||
bindtap="setFilter"
|
||||
data-status="processing"
|
||||
>
|
||||
处理中
|
||||
</button>
|
||||
<button
|
||||
class="filter-btn {{filterStatus === 'completed' ? 'active' : ''}}"
|
||||
bindtap="setFilter"
|
||||
data-status="completed"
|
||||
>
|
||||
已完成
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="task-scroll" scroll-y="{{true}}">
|
||||
<view wx:if="{{tasks.length === 0}}" class="empty-state">
|
||||
<image src="/assets/images/empty-task.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">暂无任务</text>
|
||||
</view>
|
||||
|
||||
<view wx:else>
|
||||
<task-card
|
||||
wx:for="{{filteredTasks}}"
|
||||
wx:key="id"
|
||||
taskId="{{item.id}}"
|
||||
title="{{item.title}}"
|
||||
description="{{item.description}}"
|
||||
type="{{item.type}}"
|
||||
status="{{item.status}}"
|
||||
priority="{{item.priority}}"
|
||||
createdAt="{{item.createdAt}}"
|
||||
updatedAt="{{item.updatedAt}}"
|
||||
result="{{item.result}}"
|
||||
progress="{{item.progress}}"
|
||||
bind:start="onStartTask"
|
||||
bind:complete="onCompleteTask"
|
||||
bind:retry="onRetryTask"
|
||||
bind:detail="onTaskDetail"
|
||||
bind:cancel="onCancelTask"
|
||||
/>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
181
Claw/client/wechat_app/pages/task/task.wxss
Normal file
181
Claw/client/wechat_app/pages/task/task.wxss
Normal file
@@ -0,0 +1,181 @@
|
||||
/* 任务页面样式 */
|
||||
.task-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.task-create {
|
||||
background: white;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 15rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.task-input {
|
||||
width: 100%;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 10rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
background-color: #f8f8f8;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.task-input:focus {
|
||||
border-color: #07c160;
|
||||
background-color: white;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.task-textarea {
|
||||
width: 100%;
|
||||
min-height: 120rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 10rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
background-color: #f8f8f8;
|
||||
transition: border-color 0.3s;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.task-textarea:focus {
|
||||
border-color: #07c160;
|
||||
background-color: white;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.picker {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 10rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
background-color: #f8f8f8;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.picker:focus {
|
||||
border-color: #07c160;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.picker-arrow {
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
background: linear-gradient(135deg, #07c160 0%, #06a050 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50rpx;
|
||||
padding: 30rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.submit-btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.submit-btn:disabled {
|
||||
background: #ccc;
|
||||
color: #999;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.task-list {
|
||||
flex: 1;
|
||||
background: white;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
padding: 10rpx 20rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
background: white;
|
||||
color: #666;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.filter-btn.active {
|
||||
background: #07c160;
|
||||
color: white;
|
||||
border-color: #07c160;
|
||||
}
|
||||
|
||||
.filter-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.task-scroll {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100rpx 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-state image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
Reference in New Issue
Block a user