任务协作小程序

项目名称:任务协作小程序

项目目标:开发一个基于微信小程序平台的任务协作应用,帮助团队成员更好地管理和跟踪任务,提高协作效率和质量。

功能需求:

  1. 用户管理
  • 支持微信一键登录,利用微信提供的登录能力,简化用户注册流程。
  • 用户与所属机构关联,同机构用户数据一致。
  • 个人中心允许用户查看和管理个人信息,提供头像、昵称等的修改功能。
  1. 任务看板
  • 任务看板以列表和卡片的形式展示任务,采用看板式设计,任务状态一目了然。可以拖拽移动任务卡片,便于直观地管理任务。
  • 每个任务卡片设计醒目,包括标题、负责人、截止日期等关键信息。
  • 任务卡片可以设置优先级,用不同颜色或图标表示。
  • 任务看板分为待办、进行中、已完成等多个列表,表示任务的不同状态。
  • 点击任务卡片可以查看和编辑任务详情,包括描述、子任务、附件、评论等。注意界面平滑切换,保证信息的一致性和流畅性。
  • 任务可以多层级分解为子任务,子任务完成后自动更新父任务进度,可以用进度条等形式直观展示。
  • 任务支持协作讨论和评论,可以@相关人员。
  • 所有任务操作自动记录到值班日志,注意控制权限,如任务的查看和编辑权限。
  1. 值班日志
  • 值班日志由任务操作、故障记录、手动输入三部分组成,自动归类整理汇总。
  • 字段包括但不限于日期、班次、人员、工作内容等,可以考虑允许一定程度的自定义。
  • 支持手动填写其他工作内容。
  • 可导出为格式化的 TXT 文件,文件名称格式为"值班日志_日期_班次.txt"。导出时需要鉴权,控制值班日志的查看和导出权限。
  1. 故障记录
  • 记录故障发生时间、描述、影响范围、原因等关键信息。
  • 关联到相应任务,形成闭环的故障处理流程。
  • 自动生成预防性维护任务,提高系统可靠性。
  • 关键信息自动记入值班日志,与任务、日志形成联动。
  • 提供故障统计分析功能,为运维优化提供数据支持。可利用小程序云开发的云函数和云数据库能力。
  1. 文档共享
  • 以列表形式展示共享文档。
  • 点击文档,跳转到腾讯文档等在线文档页面。
  • 注意文档的鉴权,只有相关人员可查看、编辑文档。
  1. 通知提醒
  • 新任务分配时,自动推送小程序通知,提醒相关用户。
  • 可以考虑提供多种提醒方式,如微信订阅消息、邮件、短信等。

交互设计建议:

任务看板布局清晰,可拖拽操作,便于直观管理任务。
2. 任务卡片设计醒目,关键信息一目了然,支持快速编辑。
3. 任务列表和任务详情界面平滑切换,保证信息的一致性和流畅性。
4. 界面整体布局简洁明了,突出重点信息。合理使用 tab、列表、卡片等组件。
5. 表单填写、任务操作等提供引导和及时反馈,如填写提示、完成提示、进度展示等。
6. 注意权限控制,如任务的查看和编辑权限、值班日志的查看和导出权限等。

技术建议:

  1. 采用微信小程序云开发方案,利用其提供的云函数、云存储、云数据库等能力,加速开发进程。
  2. 数据存储可以考虑 JSON 格式,便于前端解析展示。存储和获取都需要进行用户鉴权。
  3. 导出功能可由前端生成 TXT 文件,然后以二进制形式下载。后端提供数据接口支持。
  4. 评论、通知、导出等及时性要求高的功能,可以考虑合理利用缓存优化性能。
  5. 故障记录、统计分析等计算量大的功能,可以利用小程序云开发的云函数和云数据库能力。
  6. 任务看板的拖拽操作需要合理控制,避免误操作。可以考虑在拖拽时添加视觉反馈,如阴影、高亮等。
  7. 任务看板的性能优化很重要,尤其是任务数量较多时。可以考虑分页加载、懒加载等技术。
  8. 离线支持可以考虑利用小程序的本地存储,定期与服务器同步数据,保证离线时也能使用基本功能。

安全与权限:

  1. 重视数据安全,涉及隐私的数据要加密存储,传输过程也要加密。
  2. 严格控制数据访问权限,如任务的查看和编辑权限、值班日志的查看和导出权限等。
  3. 用户登录时进行身份验证,保证只有合法用户才能访问数据。
  4. 定期备份数据,制定数据恢复预案,最大限度减少数据丢失风险。
  5. 编写安全代码,防范常见的 Web 攻击,如 XSS、CSRF、SQL 注入等。

其他建议:

  1. 提供完善的帮助文档和用户指南,方便用户学习和使用。
  2. 建立用户反馈渠道,收集用户意见,不断优化产品。
  3. 制定合理的开发计划和迭代策略,逐步完善功能,提高用户满意度。
  4. 注重代码质量,编写清晰、易维护的代码,必要时编写单元测试,提高代码可靠性。
  5. 密切关注小程序平台的更新和变化,及时调整开发策略,充分利用新功能。

任务协作小程序设计了如下目录结构:

│  app.js

│  app.json

│  app.wxss

│ 

├─pages

│  ├─index

│  │      index.js

│  │      index.json

│  │      index.wxml

│  │      index.wxss

│  │     

│  ├─login

│  │      login.js

│  │      login.json

│  │      login.wxml

│  │      login.wxss

│  │     

│  ├─personal

│  │      personal.js

│  │      personal.json

│  │      personal.wxml

│  │      personal.wxss

│  │     

│  ├─taskboard

│  │      taskboard.js

│  │      taskboard.json

│  │      taskboard.wxml

│  │      taskboard.wxss

│  │     

│  ├─taskdetail

│  │      taskdetail.js

│  │      taskdetail.json

│  │      taskdetail.wxml

│  │      taskdetail.wxss

│  │     

│  ├─dutylog

│  │      dutylog.js

│  │      dutylog.json

│  │      dutylog.wxml

│  │      dutylog.wxss

│  │     

│  ├─faultrecord

│  │      faultrecord.js

│  │      faultrecord.json

│  │      faultrecord.wxml

│  │      faultrecord.wxss

│  │     

│  └─doclist

│          doclist.js

│          doclist.json

│          doclist.wxml

│          doclist.wxss

│         

├─components

│  ├─taskcard

│  │      taskcard.js

│  │      taskcard.json

│  │      taskcard.wxml

│  │      taskcard.wxss

│  │     

│  └─faultitem

│          faultitem.js

│          faultitem.json

│          faultitem.wxml

│          faultitem.wxss

│         

├─utils

│      util.js

│      auth.js

│      request.js

│     

├─services

│      user.js

│      task.js

│      dutylog.js

│      fault.js

│      doc.js

│     

└─cloud-functions

    ├─login

    │      index.js

    │      package.json

    │     

    ├─taskops

    │      index.js

    │      package.json

    │     

    ├─faultops 

    │      index.js

    │      package.json

    │     

    └─docops

            index.js

            package.json

app.js

// app.js
App({
  onLaunch: function () {
    // 初始化云开发环境
    wx.cloud.init({
      env: 'your-env-id',
      traceUser: true,
    })
  },
  globalData: {
    userInfo: null
  }
})

app.json

{
  "pages": [
    "pages/index/index",
    "pages/login/login",
    "pages/personal/personal",
    "pages/taskboard/taskboard",
    "pages/taskdetail/taskdetail",
    "pages/dutylog/dutylog",
    "pages/faultrecord/faultrecord",
    "pages/doclist/doclist"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "任务协作",
    "navigationBarTextStyle": "black"
  },
  "sitemapLocation": "sitemap.json",
  "style": "v2"
}

pages/login/login.wxml

<!--login.wxml-->
<button open-type="getUserInfo" bindgetuserinfo="onGetUserInfo">微信登录</button>

pages/login/login.js

// login.js
Page({
  onGetUserInfo: function(e) {
    if (!e.detail.userInfo) {
      // 用户拒绝授权
      return;
    }
    // 执行登录,获取用户信息
    wx.cloud.callFunction({
      name: 'login',
      data: {},
      success: res => {
        console.log('[云函数] [login] user openid: ', res.result.openid)
        app.globalData.userInfo = e.detail.userInfo
        app.globalData.openid = res.result.openid
        // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
        // 所以此处加入 callback 以防止这种情况
        if (this.userInfoReadyCallback) {
          this.userInfoReadyCallback(res)
        }
      },
      fail: err => {
        console.error('[云函数] [login] 调用失败', err)
      }
    })
  },
})

pages/taskboard/taskboard.wxml

<!--taskboard.wxml-->
<view class="container">
  <view class="task-column">
    <view class="task-column-title">待办</view>
    <view wx:for="{{todoTasks}}" wx:key="id">
      <taskcard task="{{item}}"></taskcard>
    </view>
  </view>
 
  <view class="task-column">
    <view class="task-column-title">进行中</view>
    <view wx:for="{{doingTasks}}" wx:key="id">
      <taskcard task="{{item}}"></taskcard>
    </view>
  </view>
 
  <view class="task-column">
    <view class="task-column-title">已完成</view>
    <view wx:for="{{doneTasks}}" wx:key="id">
      <taskcard task="{{item}}"></taskcard>
    </view>
  </view>
</view>

pages/taskboard/taskboard.js

// taskboard.js
const app = getApp()
Page({
  data: {
    todoTasks: [],
    doingTasks: [],
    doneTasks: [],
  },
  onLoad: function() {
    this.getTasks()
  },
  getTasks: function() { // 从云数据库获取任务数据

wx.cloud.callFunction({

name: 'taskops',

data: {

action: 'getTasks',

},

success: res => {

const tasks = res.result.data

this.setData({

todoTasks: tasks.filter(task => task.status === 'todo'),

doingTasks: tasks.filter(task => task.status === 'doing'),

doneTasks: tasks.filter(task => task.status === 'done'),

})

},

fail: err => {

console.error('[云函数] [taskops] 调用失败', err)

}

})

},

})
components/taskcard/taskcard.wxml
```html
<!--taskcard.wxml-->
<view class="task-card" bindtap="openDetail" data-id="{{task._id}}">
  <view class="task-card-title">{{task.title}}</view>
  <view class="task-card-meta">
    <text>{{task.assignee}}</text>
    <text>{{task.dueDate}}</text>
  </view>
  <view class="task-card-priority" style="background-color: {{task.priority === 'high' ? 'red' : task.priority === 'middle' ? 'yellow' : 'green'}}"></view>
</view>

components/taskcard/taskcard.js

// taskcard.js
Component({
  properties: {
    task: {
      type: Object,
      value: {},
    },
  },
  methods: {
    openDetail: function(e) {
      const taskId = e.currentTarget.dataset.id
      wx.navigateTo({
        url: `/pages/taskdetail/taskdetail?id=${taskId}`,
      })
    },
  }
})

cloud-functions/taskops/index.js

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const _ = db.command
 
// 云函数入口函数
exports.main = async (event, context) => {
  const { action, taskId, taskData } = event
  const openid = cloud.getWXContext().OPENID
  
  if (action === 'getTasks') {
    // 获取任务列表
    return await db.collection('tasks').where({
      assignee: openid,
    }).get()
  } else if (action === 'addTask') {
    // 添加任务
    return await db.collection('tasks').add({
      data: {
        ...taskData,
        assignee: openid,
        createTime: db.serverDate(),
      }
    })
  } else if (action === 'updateTask') {
    // 更新任务
    return await db.collection('tasks').doc(taskId).update({
      data: {
        ...taskData,
        updateTime: db.serverDate(),
      },
    })
  }
  // 其他操作...
}

pages/taskdetail/taskdetail.wxml

<!--taskdetail.wxml-->
<view class="container">
  <view class="task-detail-title">{{task.title}}</view>
  <view class="task-detail-desc">{{task.description}}</view>
  <view class="task-detail-meta">
    <text>负责人: {{task.assignee}}</text>
    <text>截止时间: {{task.dueDate}}</text>
    <text>优先级: {{task.priority}}</text>
  </view>
 
  <view class="task-detail-subtasks">
    <view class="task-detail-subtasks-title">子任务</view>
    <view wx:for="{{task.subtasks}}" wx:key="id">
      <view>{{item.title}}</view>
      <view>{{item.status}}</view>
    </view>
  </view>
 
  <view class="task-detail-comments">
    <view class="task-detail-comments-title">评论</view>
    <view wx:for="{{task.comments}}" wx:key="id">
      <view>{{item.author}}: {{item.content}}</view>
    </view>
    <view>
      <input placeholder="添加评论" bindinput="onCommentInput"></input>
      <button bindtap="addComment">发送</button>
    </view>
  </view>
 
  <view class="task-detail-operations">
    <button wx:if="{{task.status !== 'done'}}" bindtap="finishTask">完成任务</button>
    <button bindtap="deleteTask">删除任务</button>
  </view>
</view>

pages/taskdetail/taskdetail.js

// taskdetail.js
Page({
  data: {
    taskId: '',
    task: {},
    commentInput: '',
  },
  onLoad: function(options) {
    this.setData({
      taskId: options.id
    })
    this.getTaskDetail()
  },
  getTaskDetail: function() {
    wx.cloud.callFunction({
      name: 'taskops',
      data: {
        action: 'getTaskDetail',
        taskId: this.data.taskId,
      },
      success: res => {
        this.setData({
          task: res.result.data,
        })
      },
    })
  },
  onCommentInput: function(e) {
    this.setData({
      commentInput: e.detail.value
    })
  },
  addComment: function() {
    const comment = this.data.commentInput.trim()
    if (!comment) {
      return
    }
    wx.cloud.callFunction({
      name: 'taskops',
      data: {
        action: 'addComment',
        taskId: this.data.taskId,
        commentData: {
          content: comment,
        },
      },
      success: res => {
        this.getTaskDetail()
        this.setData({
          commentInput: ''
        })
      },
    })
  },
  finishTask: function() {
    wx.cloud.callFunction({
      name: 'taskops',
      data: {
        action: 'updateTask',
        taskId: this.data.taskId,
        taskData: {
          status: 'done',
        },
      },
      success: res => {
        this.getTaskDetail()
      },
    })
  },
  deleteTask: function() {
    wx.cloud.callFunction({
      name: 'taskops',
      data: {
        action: 'deleteTask',
        taskId: this.data.taskId,
      },
      success: res => {
        wx.navigateBack()
      },
    })
  },
})

pages/dutylog/dutylog.wxml

<!--dutylog.wxml-->
<view class="container">

pages/dutylog/dutylog.js

// dutylog.js

Page({

  data: {

    dutyLogs: [],

  },

  onLoad: function() {

    this.getDutyLogs()

  },

  getDutyLogs: function() {

    wx.cloud.callFunction({

      name: 'dutyops',

      data: {

        action: 'getDutyLogs',

      },

      success: res => {

        this.setData({

          dutyLogs: res.result.data,

        })

      },

    })

  },

  exportLogs: function() {

    wx.cloud.callFunction({

      name: 'dutyops',

      data: {

        action: 'exportDutyLogs',

      },

      success: res => {

        console.log(res.result)

        const fileUrl = res.result.fileUrl

        wx.downloadFile({

          url: fileUrl,

          success: res => {

            const filePath = res.tempFilePath

            wx.openDocument({

              filePath: filePath,

            })

          },

        })

      },

    })

  },

})

cloud-functions/dutyops/index.js

// 云函数入口文件

const cloud = require('wx-server-sdk')

cloud.init()

const db = cloud.database()

const _ = db.command

const xlsx = require('node-xlsx')

const fs = require('fs')

// 云函数入口函数

exports.main = async (event, context) => {

  const { action } = event

  if (action === 'getDutyLogs') {

    // 获取值班日志

    return await db.collection('dutyLogs').get()

  } else if (action === 'exportDutyLogs') {

    // 导出值班日志

    const logs = (await db.collection('dutyLogs').get()).data

    const data = logs.map(log => [log.date, log.shift, log.onDuty, log.content])

    const headers = ['日期', '班次', '值班人员', '工作内容']

    const sheetData = [headers, ...data]

    const sheet = xlsx.build([{name: '值班日志', data: sheetData}])

    const buffer = sheet.toString('binary')

    const today = new Date().toISOString().slice(0, 10)

    const filename = `值班日志_${today}.xlsx`

    const fileUrl = await cloud.uploadFile({

      cloudPath: filename,

      fileContent: Buffer.from(buffer, 'binary'),

    })

    return {

      fileUrl: fileUrl.fileID

    }

  }

}

以上分别是:

  1. 任务详情页面的布局和逻辑,包括任务信息展示、子任务列表、评论功能、完成和删除任务等。
  2. 值班日志页面的布局和逻辑,包括日志列表展示和日志导出功能。
  3. 值班日志相关的云函数,包括获取日志列表和导出日志到Excel等。

其中值班日志的导出用到了node-xlsx库和云存储的能力,将数据导出为Excel文件并上传到云存储,返回文件地址供小程序端下载。

故障记录和文档共享的实现思路与任务和值班日志类似,这里就不再赘述。你可以参考上述代码,结合具体的数据结构和业务需求,自行实现相关功能。

除了主要的业务页面和逻辑,小程序中还有一些其他的通用组件和工具类,例如:

components/faultitem/faultitem.wxml

<!--faultitem.wxml-->
<view class="fault-item">
  <view class="fault-item-time">{{fault.time}}</view>
  <view class="fault-item-desc">{{fault.description}}</view>
  <view class="fault-item-impact">影响: {{fault.impact}}</view>
  <view class="fault-item-operations">
    <button bindtap="resolveFault" data-id="{{fault._id}}">解决</button>
  </view>
</view>

utils/util.js

// util.js
const formatTime = date => {
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()
 
  return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
 
const formatNumber = n => {
  n = n.toString()
  return n[1] ? n : '0' + n
}
 
module.exports = {
  formatTime: formatTime
}

utils/auth.js

// auth.js
const app = getApp()
 
const checkLogin = () => {
  return new Promise((resolve, reject) => {
    if (app.globalData.userInfo) {
      resolve(app.globalData.userInfo)
    } else {
      wx.login({
        success: () => {
          wx.getUserInfo({
            success: res => {
              app.globalData.userInfo = res.userInfo
              resolve(res.userInfo)
            },
            fail: err => {
              reject(err)
            }
          })
        },
        fail: err => {
          reject(err)
        }
      })
    }
  })
}
 
const checkPermission = (scope) => {
  return new Promise((resolve, reject) => {
    wx.getSetting({
      success: res => {
        if (res.authSetting[scope]) {
          resolve()
        } else {
          wx.authorize({
            scope: scope,
            success: () => {
              resolve()
            },
            fail: err => {
              reject(err)
            }
          })
        }
      },
      fail: err => {
        reject(err)
      }
    })
  })
}
 
module.exports = {
  checkLogin: checkLogin,
  checkPermission: checkPermission,
}

这些工具类封装了一些通用的函数,如日期格式化、登录检查、权限检查等,可以在项目中复用。

最后,项目中还应该有一些配置文件,:

project.config.json: 项目配置文件,包含了项目的一些元信息和设置。
sitemap.json: 配置小程序及其页面是否允许被微信索引。

以上就是一个相对完整的任务协作小程序的主要代码组成和结构,涵盖了从前端页面到后端云函数的主要功能模块的实现。你可以在此基础上进一步完善和扩展,开发出一个满足实际需求的生产级别应用。

pages/personal/personal.wxml

<!--personal.wxml-->
<view class="container">
  <view class="personal-info">
    <image class="personal-avatar" src="{{userInfo.avatarUrl}}"></image>
    <text class="personal-nickname">{{userInfo.nickName}}</text>
  </view>
 
  <view class="personal-stats">
    <view class="personal-stats-item">
      <text class="personal-stats-num">{{todoCount}}</text>
      <text class="personal-stats-label">待办任务</text>
    </view>
    <view class="personal-stats-item">
      <text class="personal-stats-num">{{doneCount}}</text>
      <text class="personal-stats-label">已完成任务</text>
    </view>
  </view>
 
  <view class="personal-settings">
    <view class="personal-settings-item">
      <text>修改头像</text>
      <button open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">选择头像</button>
    </view>
    <view class="personal-settings-item">
      <text>修改昵称</text>
      <input value="{{userInfo.nickName}}" bindinput="onNicknameInput"></input>
      <button bindtap="updateNickname">保存</button>
    </view>
  </view>
</view>

pages/personal/personal.js

// personal.js
const app = getApp()
 
Page({
  data: {
    userInfo: {},
    todoCount: 0,
    doneCount: 0,
  },
  onLoad() {
    this.setData({
      userInfo: app.globalData.userInfo
    })
    this.getTaskStats()
  },
  getTaskStats() {
    wx.cloud.callFunction({
      name: 'taskops',
      data: {
        action: 'getTaskStats',
      },
      success: res => {
        const { todoCount, doneCount } = res.result
        this.setData({
          todoCount,
          doneCount,
        })
      },
    })
  },
  onChooseAvatar(e) {
    const { avatarUrl } = e.detail 
    this.setData({
      'userInfo.avatarUrl': avatarUrl,
    })
    this.updateUserInfo()
  },
  onNicknameInput(e) {
    this.setData({
      'userInfo.nickName': e.detail.value
    })
  },
  updateNickname() {
    this.updateUserInfo()
  },
  updateUserInfo() {
    wx.cloud.callFunction({
      name: 'userops',
      data: {
        action: 'updateUserInfo',
        userInfo: this.data.userInfo,
      },
      success: res => {
        app.globalData.userInfo = this.data.userInfo
      },
    })
  },
})

cloud-functions/userops/index.js

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
 
// 云函数入口函数
exports.main = async (event, context) => {
  const { action, userInfo } = event
 
  if (action === 'updateUserInfo') {
    const openid = cloud.getWXContext().OPENID
    return await db.collection('users').where({
      _openid: openid
    }).update({
      data: userInfo
    })
  }
}

services/user.js

// user.js
const app = getApp()
 
const updateUserInfo = async (userInfo) => {
  if (!app.globalData.openid) {
    await app.getOpenidAsync()
  }
  const db = wx.cloud.database()

  return db.collection('users').where({_openid: app.globalData.openid
}).update({
data: userInfo
})
}

const getUserInfo = async () => {
if (!app.globalData.openid) {
await app.getOpenidAsync()
}
const db = wx.cloud.database()
const res = await db.collection('users').where({
_openid: app.globalData.openid
}).get()
return res.data[0]
}

module.exports = {
updateUserInfo,
getUserInfo,
}

 
services/task.js
```javascript
// task.js
const db = wx.cloud.database()
const _ = db.command
 
const addTask = async (task) => {
  return db.collection('tasks').add({
    data: {
      ...task,
      status: 'todo',
      createTime: db.serverDate(),
    }
  })
}
 
const updateTask = async (id, task) => {
  return db.collection('tasks').doc(id).update({
    data: {
      ...task,
      updateTime: db.serverDate(),
    }
  })
}
 
const deleteTask = async (id) => {
  return db.collection('tasks').doc(id).remove()
}
 
const getTasks = async (status) => {
  return db.collection('tasks').where({
    status,
  }).get()
}
 
const getTaskStats = async (openid) => {
  const todoRes = await db.collection('tasks').where({
    _openid: openid,
    status: 'todo',
  }).count()
  const doneRes = await db.collection('tasks').where({
    _openid: openid,
    status: 'done',
  }).count()
  return {
    todoCount: todoRes.total,
    doneCount: doneRes.total,
  }
}
 
module.exports = {
  addTask,
  updateTask,
  deleteTask,
  getTasks,
  getTaskStats,
}

app.js

// app.js
App({
  globalData: {
    userInfo: null,
    openid: null,
  },
  onLaunch() {
    this.initCloud()
  },
  initCloud() {
    wx.cloud.init({
      env: 'your-env-id',
    })
  },
  getOpenidAsync() {
    return new Promise((resolve, reject) => {
      wx.cloud.callFunction({
        name: 'login',
      }).then(res => {
        this.globalData.openid = res.result.openid
        resolve(res.result.openid)
      }).catch(err => {
        console.error('getOpenidAsync error:', err)
        reject(err)
      })
    })
  },
})
 

pages/faultrecord/faultrecord.wxml

<!--faultrecord.wxml-->
<view class="container">
  <view class="fault-list">
    <view wx:for="{{faults}}" wx:key="id">
      <faultitem fault="{{item}}"></faultitem>
    </view>
  </view>
 
  <view class="fault-add">
    <button bindtap="addFault">添加故障</button>
  </view>
</view>

pages/faultrecord/faultrecord.js

// faultrecord.js
const { getFaults, addFault, resolveFault } = require('../../services/fault')
 
Page({
  data: {
    faults: [],
  },
  onLoad() {
    this.getFaultList()
  },
  async getFaultList() {
    const faults = await getFaults()
    this.setData({ faults })
  },
  addFault() {
    wx.navigateTo({
      url: '/pages/faultdetail/faultdetail',
    })
  },
  async handleResolveFault(e) {
    const { id } = e.detail
    await resolveFault(id)
    this.getFaultList()
  },
})

pages/faultdetail/faultdetail.wxml

<!--faultdetail.wxml-->
<view class="container">
  <view class="fault-detail-form">
    <view class="fault-detail-form-item">
      <text>故障时间:</text>
      <picker mode="date" value="{{fault.time}}" bindchange="onTimeChange">
        <view>{{fault.time}}</view>
      </picker>
    </view>
    <view class="fault-detail-form-item">
      <text>故障描述:</text>
      <textarea value="{{fault.description}}" bindinput="onDescInput"></textarea>
    </view>
    <view class="fault-detail-form-item">
      <text>影响范围:</text>
      <input value="{{fault.impact}}" bindinput="onImpactInput"></input>
    </view>
  </view>
 
  <view class="fault-detail-actions">
    <button bindtap="saveFault">保存</button>
  </view>
</view>

pages/faultdetail/faultdetail.js

// faultdetail.js
const { addFault } = require('../../services/fault')
 
Page({
  data: {
    fault: {
      time: '',
      description: '',
      impact: '',
    },
  },
  onLoad(options) {
    if (options.id) {
      // 编辑模式
      // 获取故障详情
    } else {
      // 新增模式
      this.setData({
        fault: {
          time: this.formatDate(new Date()),
          description: '',
          impact: '',
        },
      })
    }
  },
  formatDate(date) {
    const year = date.getFullYear()
    const month = date.getMonth() + 1
    const day = date.getDate()
    return `${year}-${month}-${day}`
  },
  onTimeChange(e) {
    this.setData({
      'fault.time': e.detail.value,
    })
  },
  onDescInput(e) {
    this.setData({
      'fault.description': e.detail.value,
    })
  },
  onImpactInput(e) {
    this.setData({
      'fault.impact': e.detail.value,
    })
  },
  async saveFault() {
    await addFault(this.data.fault)
    wx.navigateBack()
  },
})

pages/doclist/doclist.wxml

<!--doclist.wxml-->
pages/doclist/doclist.js
```javascript
// doclist.js
const { getDocs } = require('../../services/doc')
 
Page({
  data: {
    docs: [],
  },
  onLoad() {
    this.getDocList()
  },
  async getDocList() {
    const docs = await getDocs()
    this.setData({ docs })
  },
  openDoc(e) {
    const { url } = e.currentTarget.dataset
    wx.navigateTo({
      url: `/pages/webview/webview?url=${url}`,
    })
  },
})

pages/webview/webview.wxml

<!--webview.wxml-->
<web-view src="{{url}}"></web-view>

pages/webview/webview.js

// webview.js
Page({
  data: {
    url: '',
  },
  onLoad(options) {
    const { url } = options
    this.setData({ url })
  },
})

services/fault.js

// fault.js
const db = wx.cloud.database()
 
const addFault = async (fault) => {
  return db.collection('faults').add({
    data: {
      ...fault,
      status: 'unsolved',
      createTime: db.serverDate(),
    }
  })
}
 
const getFaults = async () => {
  return db.collection('faults').orderBy('createTime', 'desc').get()
}
 
const resolveFault = async (id) => {
  return db.collection('faults').doc(id).update({
    data: {
      status: 'resolved',
      resolveTime: db.serverDate(),
    }
  })
}
 
module.exports = {
  addFault,
  getFaults,
  resolveFault,
}

services/doc.js

// doc.js
const db = wx.cloud.database()
 
const addDoc = async (doc) => {
  return db.collection('docs').add({
    data: {
      ...doc,
      createTime: db.serverDate(),
      updateTime: db.serverDate(),
    }
  })
}
 
const getDocs = async () => {
  return db.collection('docs').orderBy('updateTime', 'desc').get()
}
 
module.exports = {
  addDoc,
  getDocs,
}

cloud-functions/faultops/index.js

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const _ = db.command
 
// 云函数入口函数
exports.main = async (event, context) => {
  const { action, faultId, faultData } = event
 
  if (action === 'addFault') {
    return await db.collection('faults').add({
      data: {
        ...faultData,
        status: 'unsolved',
        createTime: db.serverDate(),
      }
    })
  } else if (action === 'resolveFault') {
    return await db.collection('faults').doc(faultId).update({
      data: {
        status: 'resolved',
        resolveTime: db.serverDate(),
      }
    })
  }
}

cloud-functions/docops/index.js

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const _ = db.command
 

// 云函数入口函数
exports.main = async (event, context) => {
const { action, docData } = event

if (action === 'addDoc') {
return await db.collection('docs').add({
data: {
...docData,
createTime: db.serverDate(),
updateTime: db.serverDate(),
}
})
}
}


                
  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值