首页 > 其他分享 >前端【uniapp】06-uniapp【练习项目 · 神领物流】【任务【交付】【回车登记】【已完成列表】】

前端【uniapp】06-uniapp【练习项目 · 神领物流】【任务【交付】【回车登记】【已完成列表】】

时间:2024-04-23 09:12:54浏览次数:21  
标签:uniapp 06 ... text value import ref id 神领

uni-app(神领物流)项目实战

学习目标:

  • 能够独立完成回交付、回车登记的功能

  • 能够自定义回车登记交互组件

  • 能够使用 Pinia 实现组件间数据共享

  • 能够打包发布 H5、小程序和 App 项目应用

  • 能够配置App的图标及启动屏幕

一、【神领物流】任务

1、交付

  司机在将货物运达目的地后会与接货人办理交付手续,在手续办结后司机需要将交付相关的单据及交付现场的照片上传管理后台。

  该功能模块的实现步骤与提货是完全一致的,区别在于所调用的接口不同,接口的详细说明在这里。

1.1 上传图片

  使用 uni-file-picker 将图片上传到云空间,务必保证已经创建并关联了 uniCloud 空间

 1 <!-- subpkg_task/delivery/index.vue -->
 2 <script setup>
 3   import { ref } from 'vue'
 4   import { onl oad } from '@dcloudio/uni-app'
 5   // 提货凭证照片
 6   const receiptPictrues = ref([])
 7   // 提货商品照片
 8   const goodsPictrues = ref([])
 9 </script>
10 <template>
11   <view class="page-container">
12     <view class="receipt-info">
13       <uni-file-picker
14         v-model="receiptPictrues"
15         file-extname="jpg,webp,gif,png"
16         limit="3"
17         title="请拍照上传回单凭证"
18       ></uni-file-picker>
19       <uni-file-picker
20         v-model="goodsPictrues"
21         file-extname="jpg,webp,gif,png"
22         limit="3"
23         title="请拍照上传货品照片"
24       ></uni-file-picker>
25     </view>
26     <button disabled class="button">提交</button>
27   </view>
28 </template>

1.2 表单数据

  本小节需要完成两个任务,一是处理接口所需的参数,二是验证是否至少上传了一张图片。

  1. 数据验证

 1 <!-- subpkg_task/delivery/index.vue -->
 2 <script setup>
 3   import { ref, computed } from 'vue'
 4   import { onl oad } from '@dcloudio/uni-app'
 5 ​
 6   // 任务ID
 7   const id = ref('')
 8 ​
 9   // 提货凭证照片
10   const receiptPictrues = ref([])
11   // 提货商品照片
12   const goodsPictrues = ref([])
13 ​
14   // 凭证和商品都至少上传一张图片
15   const enableSubmit = computed(() => {
16     return goodsPictrues.value.length > 0 && receiptPictrues.value.length > 0
17   })
18 </script>
19 <template>
20   <view class="page-container">
21     ...
22     <button :disabled="!enableSubmit" class="button">提交</button>
23   </view>
24 </template>
  1. 处理表单的数据

  • 任务ID是通地址参数传递的

  • certificatePictureList 数组只包含 url 属性

  • deliverPictureList 数组只包含 url 属性

 1 <!-- subpkg_task/delivery/index.vue -->
 2 <script setup>
 3   import { ref, computed } from 'vue'
 4   import { onl oad } from '@dcloudio/uni-app'
 5   
 6   // 任务ID
 7   const id = ref('')
 8 ​
 9   // 提货凭证照片
10   const receiptPictrues = ref([])
11   // 过滤掉多余的数据,只保留 url
12   const certificatePictureList = computed(() => {
13     return receiptPictrues.value.map(({ url }) => {
14       return { url }
15     })
16   })
17 ​
18   // 提货商品照片
19   const goodsPictrues = ref([])
20   // 过滤掉多余的数据,只保留 url
21   const deliverPictureList = computed(() => {
22     return goodsPictrues.value.map(({ url }) => {
23       return { url }
24     })
25   })
26 ​
27     // 省略中间部分代码...
28 ​
29   // 获取地址中的参数
30   onl oad((query) => {
31     // 任务ID
32     id.value = query.value
33   })
34 </script>
35 <template>
36   <view class="page-container">
37     ...
38   </view>
39 </template>

1.3 提交数据

  将云空间存储图片的路径发送给服务端接口即可。

  1. 封装调用接口的方法

 1 // apis/task.js
 2 ​
 3 export default {
 4   // 省略中间部分代码...
 5   
 6   /**
 7    * 交付
 8    * @property {Object} data - 接口参数
 9    */
10   deliver(data) {
11     if (!data.id) return
12     return uniFetch.post('/driver/tasks/deliver', data)
13   },
14 }
  1. 在交付页面点击提交按钮后提交数据

 1 <!-- subpkg_task/delivery/index.vue -->
 2 <script setup>
 3   import { ref, computed } from 'vue'
 4   import { onl oad } from '@dcloudio/uni-app'
 5   import taskApi from '@/apis/task'
 6 ​
 7     // 省略中间部分代码...
 8 ​
 9   // 获取地址中的参数
10   onl oad((query) => {
11     // 任务ID
12     id.value = query.value
13   })
14   
15   // 提交交付数据
16   async function onSubmitForm() {
17     // 表单数据
18     const formData = {
19       id: id.value,
20       certificatePictureList: certificatePictureList.value,
21       deliverPictureList: deliverPictureList.value,
22     }
23     // 调用接口
24     const { code } = await taskApi.deliver(formData)
25     if (code !== 200) return uni.utils.toast('上传图片失败!')
26     // 去到任务列表(查看在途任务)
27     uni.reLaunch({ url: '/pages/task/index' })
28   }
29 </script>
30 <template>
31   <view class="page-container">
32     ...
33     <button @click="onSubmitForm" :disabled="!enableSubmit" class="button">提交</button>
34   </view>
35 </template>

1.4 在途列表

  司机在完成运输交付后,运输任的状态会变成 4 ,此时在【在途列表】和【任务详情】中显示的操作应该是【回车登记】。

 1 <!-- pages/task/components/delivery/index.vue -->
 2 <script setup>
 3   // 此处不需要添加代码
 4 </script>
 5 <template>
 6     <scroll-view scroll-y refresher-enabled class="scroll-view">
 7     <view class="scroll-view-wrapper">
 8         <view v-for="delivery in deliveryList" :key="delivery.id" class="task-card">
 9         ...
10         <view class="footer">
11           <view class="label">到货时间</view>
12           <view class="time">{{ delivery.planArrivalTime }}</view>
13           <navigator
14             v-if="delivery.status === 2"
15             hover-class="none"
16             :url="`/subpkg_task/delivery/index?id=${delivery.id}`"
17             class="action"
18           >
19             交付
20           </navigator>
21           <navigator
22             v-if="delivery.status === 4"
23             hover-class="none"
24             :url="`/subpkg_task/record/index?transportTaskId=${delivery.transportTaskId}`"
25             class="action"
26           >
27             回车登记
28           </navigator>
29         </view>
30       </view>
31       <view v-if="isEmpty" class="task-blank">无在途货物</view>
32     </view>
33   </scroll-view>
34 </template>

1.5 任务详情

  司机在交付运输任务时上传了交付相关的凭证和物品照片,此时到详情中进行展示了。

 1 <!-- subpkg_task/detail/index.vue -->
 2 <script setup>
 3   // 此时不需要添加代码...
 4 </script>
 5 <template>
 6   <view class="page-container">
 7     <view class="search-bar">
 8       <!-- #ifdef H5 -->
 9       <text class="iconfont icon-search"></text>
10       <!-- #endif -->
11 ​
12       <!-- #ifdef APP-PLUS | MP -->
13       <text class="iconfont icon-scan"></text>
14       <!-- #endif -->
15       <input class="input" type="text" placeholder="输入运单号" />
16     </view>
17     <scroll-view scroll-y class="task-detail">
18       <view class="scroll-view-wrapper">
19         <view class="basic-info panel">
20           <view class="panel-title">基本信息</view>
21           ...
22         </view>
23 ​
24         <view v-if="taskDetail.exceptionList?.length" class="except-info panel">
25           <view class="panel-title">异常信息</view>
26           ...
27         </view>
28 ​
29         <view v-if="taskDetail.status >= 2" class="panel pickup-info">
30           <view class="panel-title">提货信息</view>
31           ...
32         </view>
33 ​
34         <view
35           v-if="taskDetail.status === 4 || taskDetail.status === 6"
36           class="delivery-info panel"
37         >
38           <view class="panel-title">交货信息</view>
39           <view class="label">交货凭证</view>
40           <view class="pictures">
41             <image
42               v-for="certificate in taskDetail.certificatePictureList"
43               :key="certificate.url"
44               class="picture"
45               :src="certificate.url"
46             ></image>
47             <view v-if="false" class="picture-blank">暂无图片</view>
48           </view>
49           <view class="label">货品照片</view>
50           <view class="pictures">
51             <image
52               v-for="delivery in taskDetail.deliverPictureList"
53               :key="delivery.url"
54               class="picture"
55               :src="delivery.url"
56             ></image>
57             <view v-if="false" class="picture-blank">暂无图片</view>
58           </view>
59         </view>
60       </view>
61     </scroll-view>
62         ...
63   </view>
64 </template>

  上述代码中在运输任务状态处于 46 时都是允许查看交付信息中的图片的。

2、回车登记

  回车登记是在司机完运输交付要完成的最后一项操作,该功能是让司机对整个运输过程情况做补充说明,如运输途中有没有交通违章、交通事故、车辆故障等。

2.1 出车时间

  出车时间需要通过地址参数进行传递,在途列表和任务详情都会跳转到回车登记页面,我们去补充上地址参数的传递。

  1. 在途列表页面

 1 <!-- pages/task/components/delivery/index.vue -->
 2 <script setup>
 3   // 此处不需要添加代码
 4 </script>
 5 <template>
 6     <scroll-view scroll-y refresher-enabled class="scroll-view">
 7     <view class="scroll-view-wrapper">
 8         <view v-for="delivery in deliveryList" :key="delivery.id" class="task-card">
 9         ...
10         <view class="footer">
11           <view class="label">到货时间</view>
12           <view class="time">{{ delivery.planArrivalTime }}</view>
13           ...
14           <navigator
15             v-if="delivery.status === 4"
16             hover-class="none"
17             :url="`/subpkg_task/record/index?transportTaskId=${delivery.transportTaskId}&actualDepartureTime=${delivery.actualDepartureTime}`"
18             class="action"
19           >
20             回车登记
21           </navigator>
22         </view>
23       </view>
24       <view v-if="isEmpty" class="task-blank">无在途货物</view>
25     </view>
26   </scroll-view>
27 </template>
  1. 任务详情页面

 1 <!-- subpkg_task/detail/index.vue -->
 2 <script setup>
 3   // 此时不需要添加代码...
 4 </script>
 5 <template>
 6   <view class="page-container">
 7     <view class="search-bar">
 8             ...
 9     </view>
10     <scroll-view scroll-y class="task-detail">
11       <view class="scroll-view-wrapper">
12         ...
13       </view>
14     </scroll-view>
15         ...
16     <view class="toolbar" v-if="taskDetail.status === 4">
17       <navigator
18         :url="`/subpkg_task/record/index?transportTaskId=${taskDetail.transportTaskId}&actualDepartureTime=${taskDetail.actualDepartureTime}`"
19         hover-class="none"
20         class="button primary block"
21       >
22         回车登记
23       </navigator>
24     </view>
25   </view>
26 </template>
  1. 在 onl oad 生命周期中获取地址参数

 1 <!-- subpkg_task/record/index.vue -->
 2 <script setup>
 3   import { ref } from 'vue'
 4   import { onl oad } from '@dcloudio/uni-app'
 5     
 6   // 省略中间部分代码...
 7 ​
 8   // 获取地址参数
 9   onl oad((query) => {
10     // 查看地址中的参数
11    consolel.log(query)
12   })
13 </script>

2.2 回车时间

  回车时间用到了扩展组件 uni-datetime-picker,该组件提供了 v-model 来获取用户所选择的日期时间。

 1 <!-- subpkg_task/record/index.vue -->
 2 <script setup>
 3   import { ref, computed } from 'vue'
 4   import { onl oad } from '@dcloudio/uni-app'
 5 ​
 6   // 省略中间部分代码...
 7 ​
 8   // 回车时间(临时性的)
 9   const endTime = ref('')
10 ​
11   // 省略中间部分代码...
12   
13 </script>
14 <template>
15   <view class="page-container">
16     <scroll-view class="scroll-view" scroll-y>
17       <view class="scroll-view-wrapper">
18         <uni-list class="base-info">
19           ...
20           <uni-list-item show-arrow title="回车时间">
21             <template v-slot:footer>
22               <uni-datetime-picker v-model="endTime">
23                 <view class="picker-value">{{ endTime || '请选择' }}</view>
24               </uni-datetime-picker>
25             </template>
26           </uni-list-item>
27         </uni-list>
28                 ...
29       </view>
30     </scroll-view>
31         ...
32   </view>
33 </template>

2.3 组件交互

  交通违章、车辆故障、交通事故都是独立的组件,并且这些组件中包含了两个交互,一个是显示/隐藏选项、另一个是用户点击选择选项,以交通违章为例给大家进行说明。

  1. 显示/隐藏选项

 1 <!-- subpkg_task/record/components/vehicle-violation.vue -->
 2 <script setup>
 3   import { ref } from 'vue'
 4 ​
 5   // 是不显示详细的选项
 6   const show = ref(false)
 7 ​
 8  // 省略了中间部分代码...
 9 ​
10   function onRadioChange(ev) {
11     // 展开详细的选项
12     show.value = !!parseInt(ev.detail.value)
13   }
14 </script>
15 <template>
16   <view class="vehicle-panel">
17     <view class="vehicle-panel-header">
18       <view class="label">交通违章</view>
19       <radio-group class="radio-group" @change="onRadioChange">
20         <label class="label">
21           <radio class="radio" value="1" color="#EF4F3F" />
22           <text>是</text>
23         </label>
24         <label class="label">
25           <radio class="radio" checked value="0" color="#EF4F3F" />
26           <text>否</text>
27         </label>
28       </radio-group>
29     </view>
30     <view v-show="show" class="vehicle-panel-body">
31       ...
32     </view>
33   </view>
34 </template>
  1. 自定义公共组件,在交通违章、车辆故障、交通事件中包含了共同点击选择的交互,我们将这部分的交互封装到组件当中。

 1 <!-- subpkg_task/record/components/vehicle-options.vue -->
 2 <script setup>
 3   import { ref } from 'vue'
 4 ​
 5   // 当前被选中选项的索引值
 6   const tabIndex = ref(-1)
 7 ​
 8   // 接收传入组件的数据
 9   const props = defineProps({
10     types: Array,
11   })
12 ​
13   // 点击选中选项
14   function onOptionSelect(index) {
15     // 高亮显示选中的选项
16     tabIndex.value = index
17   }
18 </script>
19 ​
20 <template>
21   <view class="vehicle-options">
22     <view
23       class="option"
24       :class="{ active: tabIndex === index }"
25       v-for="(option, index) in props.types"
26       :key="option.id"
27       @click="onOptionSelect(index)"
28     >
29       {{ option.text }}
30     </view>
31   </view>
32 </template>
33 ​
34 <style lang="scss" scoped>
35   .vehicle-options {
36     display: flex;
37     flex-wrap: wrap;
38     font-size: $uni-font-size-small;
39 ​
40     .option {
41       width: 180rpx;
42       height: 70rpx;
43       text-align: center;
44       line-height: 72rpx;
45       margin-top: 30rpx;
46       margin-right: 38rpx;
47       color: $uni-secondary-color;
48       border: 2rpx solid $uni-bg-color;
49       background-color: $uni-bg-color;
50       border-radius: 20rpx;
51 ​
52       &:nth-child(3n) {
53         margin-right: 0;
54       }
55 ​
56       &.active {
57         color: $uni-primary;
58         border: 2rpx solid $uni-primary;
59         background-color: #ffe0dd;
60       }
61     }
62   }
63 </style>

  组件封装完毕后,分别在交通违章、车辆事故、交通事故页面引入该组件

========================== 直接拷贝以下部分代码 ===========================

  1 <!-- subpkg_task/record/components/vehicle-violation.vue -->
  2 <script setup>
  3   import { ref } from 'vue'
  4   import vehicleOptions from './vehicle-options'
  5 ​
  6   // 是不显示详细的选项
  7   const show = ref(false)
  8   // 构造数据
  9   const initialData = ref([
 10     {
 11       title: '违章类型',
 12       key: 'breakRulesType',
 13       types: [
 14         { id: 1, text: '闯红灯' },
 15         { id: 2, text: '无证驾驶' },
 16         { id: 3, text: '超载' },
 17         { id: 4, text: '酒后驾驶' },
 18         { id: 5, text: '超速驾驶' },
 19         { id: 6, text: '其它' },
 20       ],
 21     },
 22     {
 23       title: '罚款金额',
 24       key: 'penaltyAmount',
 25       types: [
 26         { id: '0', text: '0元' },
 27         { id: '100', text: '100元' },
 28         { id: '200', text: '200元' },
 29         { id: '300', text: '300元' },
 30         { id: '500', text: '500元' },
 31         { id: '1000', text: '1000元' },
 32         { id: '2000', text: '2000元' },
 33       ],
 34     },
 35     {
 36       title: '扣分',
 37       key: 'deductPoints',
 38       types: ['0分', '1分', '2分', '3分', '6分', '12分'],
 39       types: [
 40         { id: '0', text: '0分' },
 41         { id: '1', text: '1分' },
 42         { id: '2', text: '2分' },
 43         { id: '3', text: '3分' },
 44         { id: '6', text: '6分' },
 45         { id: '12', text: '12分' },
 46       ],
 47     },
 48   ])
 49     
 50   // 显示/隐藏选项
 51   function onRadioChange(ev) {
 52     // 展开详细的选项
 53     show.value = !!parseInt(ev.detail.value)
 54   }
 55 </script>
 56 ​
 57 <template>
 58   <view class="vehicle-panel">
 59     <view class="vehicle-panel-header">
 60       <view class="label">交通违章</view>
 61       <radio-group class="radio-group" @change="onRadioChange">
 62         <label class="label">
 63           <radio class="radio" value="1" color="#EF4F3F" />
 64           <text>是</text>
 65         </label>
 66         <label class="label">
 67           <radio class="radio" checked value="0" color="#EF4F3F" />
 68           <text>否</text>
 69         </label>
 70       </radio-group>
 71     </view>
 72     <view v-show="show" class="vehicle-panel-body">
 73       <uni-list>
 74         <uni-list-item
 75           v-for="item in initialData"
 76           direction="column"
 77           :border="false"
 78           :title="item.title"
 79         >
 80           <template v-slot:footer>
 81             <vehicle-options :types="item.types" />
 82           </template>
 83         </uni-list-item>
 84       </uni-list>
 85     </view>
 86   </view>
 87 </template>
 88 <style lang="scss" scoped>
 89   @import './styles/vehicle-panel.scss';
 90   @import './styles/vehicle-violation.scss';
 91 </style>
 92 
 93 <!-- subpkg_task/record/components/vehicle-breakdown.vue -->
 94 <script setup>
 95   import { ref } from 'vue'
 96   import vehicleOptions from './vehicle-options'
 97 ​
 98   // 是不显示详细的选项
 99   const show = ref(false)
100   // 故障类型
101   const types = ref([
102     { id: 1, text: '启动困难' },
103     { id: 2, text: '不着车' },
104     { id: 3, text: '漏油' },
105     { id: 4, text: '漏水' },
106     { id: 5, text: '照明失灵' },
107     { id: 6, text: '有异响' },
108     { id: 7, text: '排烟异常' },
109     { id: 8, text: '温度异常' },
110     { id: 9, text: '其他' },
111   ])
112 ​
113   function onRadioChange(ev) {
114     // 展开详细的选项
115     show.value = ev.detail.value
116   }
117 </script>
118 ​
119 <template>
120   <view class="vehicle-panel">
121     <view class="vehicle-panel-header">
122       <view class="label">车辆故障</view>
123       <radio-group class="radio-group" @change="onRadioChange">
124         <label class="label">
125           <radio class="radio" value="1" color="#EF4F3F" />
126           <text>是</text>
127         </label>
128         <label class="label">
129           <radio class="radio" checked value="0" color="#EF4F3F" />
130           <text>否</text>
131         </label>
132       </radio-group>
133     </view>
134     <view v-show="show" class="vehicle-panel-body">
135       <uni-list>
136         <uni-list-item direction="column" :border="false" title="故障类型">
137           <template v-slot:footer>
138             <vehicle-options :types="types" />
139             <view class="textarea-wrapper">
140               <textarea
141                 class="textarea"
142                 placeholder="请输入异常描述"
143               ></textarea>
144               <view class="words-count">0/50</view>
145             </view>
146           </template>
147         </uni-list-item>
148         <uni-list-item direction="column" :border="false" title="请拍照">
149           <template v-slot:footer>
150             <uni-file-picker limit="6"></uni-file-picker>
151           </template>
152         </uni-list-item>
153       </uni-list>
154     </view>
155   </view>
156 </template>
157 ​
158 <style lang="scss" scoped>
159   @import './styles/vehicle-panel.scss';
160   @import 'styles/vehicle-breakdown.scss';
161 </style>
162 
163 <!-- subpkg_task/record/components/vehicle-accident.vue -->
164 <script setup>
165   import { ref } from 'vue'
166   import vehicleOptions from './vehicle-options'
167 ​
168   // 是不显示详细的选项
169   const show = ref(false)
170 ​
171   // 事故类型
172   const types = ref([
173     { id: 1, text: '直行事故' },
174     { id: 2, text: '追尾事故' },
175     { id: 3, text: '超车事故' },
176     { id: 4, text: '左转弯事故' },
177     { id: 5, text: '右转弯事故' },
178     { id: 6, text: '弯道事故' },
179     { id: 7, text: '坡道事故' },
180     { id: 8, text: '会车事故' },
181     { id: 9, text: '其他' },
182   ])
183 ​
184   function onRadioChange(ev) {
185     // 展开详细的选项
186     show.value = ev.detail.value
187   }
188 </script>
189 ​
190 <template>
191   <view class="vehicle-panel">
192     <view class="vehicle-panel-header">
193       <view class="label">交通事故</view>
194       <radio-group class="radio-group" @change="onRadioChange">
195         <label class="label">
196           <radio class="radio" value="1" color="#EF4F3F" />
197           <text>是</text>
198         </label>
199         <label class="label">
200           <radio class="radio" checked value="0" color="#EF4F3F" />
201           <text>否</text>
202         </label>
203       </radio-group>
204     </view>
205     <view v-show="show" class="vehicle-panel-body">
206       <uni-list>
207         <uni-list-item direction="column" :border="false" title="事故类型">
208           <template v-slot:footer>
209             <vehicle-options :types="types" />
210             <view class="textarea-wrapper">
211               <textarea
212                 class="textarea"
213                 placeholder="请输入异常描述"
214               ></textarea>
215               <view class="words-count">0/50</view>
216             </view>
217           </template>
218         </uni-list-item>
219         <uni-list-item direction="column" :border="false" title="请拍照">
220           <template v-slot:footer>
221             <uni-file-picker limit="6"></uni-file-picker>
222           </template>
223         </uni-list-item>
224       </uni-list>
225     </view>
226   </view>
227 </template>
228 ​
229 <style lang="scss" scoped>
230   @import './styles/vehicle-panel.scss';
231   @import './styles/vehicle-accident.scss';
232 </style>

  以上代码大家就直接粘贴到项目中替换掉原来的代码就可以了,后续我会去更新 git 仓库中的静态模板代码。

========================== 直接拷贝以上部分代码 ===========================

2.4 交通违章

  用户点击选择了选项后,我们需要记录用户所选择的是哪个类型的哪个值。

  1. 用户选择的哪个值 ,在用户进行点击时通过参数传入

 1 <!-- subpkg_task/record/components/vehicle-options.vue -->
 2 <script setup>
 3   import { ref } from 'vue'
 4 ​
 5     // 此处省略中间部分代码...
 6 ​
 7   // 点击选中选项
 8   function onOptionSelect(index, text) {
 9     // 高亮显示选中的选项
10     tabIndex.value = index
11     // 用户选择了哪个值
12     console.log(text)
13   }
14 </script>
15 ​
16 <template>
17   <view class="vehicle-options">
18     <view
19       class="option"
20       :class="{ active: tabIndex === index }"
21       v-for="(option, index) in props.types"
22       :key="option.id"
23       @click="onOptionSelect(index, option.text)"
24     >
25       {{ option.text }}
26     </view>
27   </view>
28 </template>
  1. 确定用户选择了哪个类型,为组件自定义一个属性 dataKey 通过 dataKey 来区分用户当前点击的是哪个类型

 1 <!-- subpkg_task/record/components/vehicle-options.vue -->
 2 <script setup>
 3   import { ref } from 'vue'
 4 ​
 5     // 此处省略中间部分代码...
 6   
 7   // 接收传入组件的数据
 8   const props = defineProps({
 9     types: Array,
10     dataKey: String,
11   })
12 ​
13   // 点击选中选项
14   function onOptionSelect(index, text) {
15     // 高亮显示选中的选项
16     tabIndex.value = index
17     
18     // 用户选择的是哪个类型
19     console.log(props.dataKey)
20     // 用户选择了哪个值
21     console.log(text)
22   }
23 </script>
24 ​
25 <template>
26   <view class="vehicle-options">
27     <view
28       class="option"
29       :class="{ active: tabIndex === index }"
30       v-for="(option, index) in props.types"
31       :key="option.id"
32       @click="onOptionSelect(index, option.text)"
33     >
34       {{ option.text }}
35     </view>
36   </view>
37 </template>

  在应用组件 vehicle-options 组件,为其传入一个 data-key 属性,该属性的值用来区分所选择的值是哪个类型的。

 1 <!-- subpkg_task/record/components/vehicle-violation.vue -->
 2 <script setup>
 3     // 这里不需要添加新代码...
 4 </script>
 5 ​
 6 <template>
 7   <view class="vehicle-panel">
 8     <view class="vehicle-panel-header">
 9       ....
10     </view>
11     <view v-show="show" class="vehicle-panel-body">
12       <uni-list>
13         <uni-list-item
14           v-for="item in initialData"
15           direction="column"
16           :border="false"
17           :title="item.title"
18         >
19           <template v-slot:footer>
20             <vehicle-options :data-key="item.key" :types="item.types" />
21           </template>
22         </uni-list-item>
23       </uni-list>
24     </view>
25   </view>
26 </template>

2.5 车辆故障

  用户所选择的车辆故障的数据也需要记录下来,同样的需要传入 data-key 属性

 1 <!-- subpkg_task/record/components/vehicle-breakdown.vue -->
 2 <script setup>
 3     // 这里不需要添加新代码...
 4 </script>
 5 <template>
 6   <view class="vehicle-panel">
 7     <view class="vehicle-panel-header">
 8       ...
 9     </view>
10     <view v-show="show" class="vehicle-panel-body">
11       <uni-list>
12         <uni-list-item direction="column" :border="false" title="故障类型">
13           <template v-slot:footer>
14             <vehicle-options data-key="faultType" :types="types" />
15             ...
16           </template>
17         </uni-list-item>
18         ...
19       </uni-list>
20     </view>
21   </view>
22 </template>

2.6 交通事故

  用户所选择的交通事故的数据也需要记录下来,同样的需要传入 data-key 属性

 1 <!-- subpkg_task/record/components/vehicle-accident.vue -->
 2 <script setup>
 3     // 这里不需要添加新代码...
 4 </script>
 5 <template>
 6   <view class="vehicle-panel">
 7     <view class="vehicle-panel-header">
 8       ...
 9     </view>
10     <view v-show="show" class="vehicle-panel-body">
11       <uni-list>
12         <uni-list-item direction="column" :border="false" title="事故类型">
13           <template v-slot:footer>
14             <vehicle-options data-key="accidentType" :types="types" />
15             ...
16           </template>
17         </uni-list-item>
18         ...
19       </uni-list>
20     </view>
21   </view>
22 </template>

2.7 表单数据

  在处理回车登记数时涉及到了组件的数据的传递,我们来通过 Pinia 来解决组件数据通信的问题。

  1. 定义 Store 及数据

 1 // stores/task.js
 2 import { ref } from 'vue'
 3 import { defineStore } from 'pinia'
 4 ​
 5 export const useTaskStore = defineStore('task', () => {
 6   // 这里定义的数据全部是接口所需要的数据
 7   const recordData = ref({
 8     id: '',
 9     startTime: '',
10     endTime: '',
11     /*** 违章 ***/
12     isBreakRules: false,
13     breakRulesType: null,
14     penaltyAmount: null,
15     deductPoints: null,
16     /*** 违章 ***/
17 ​
18     /*** 故障 ***/
19     isFault: false,
20     faultType: null,
21     faultDescription: '',
22     faultImagesList: [],
23     /*** 故障 ***/
24 ​
25     /*** 事故 ***/
26     isAccident: false,
27     accidentType: null,
28     accidentDescription: '',
29     accidentImagesList: [],
30     /*** 事故 ***/
31   })
32 ​
33   return { recordData }
34 })
  1. 将用户点击选择的选项存入 Pinia 中

 1 <!-- subpkg_task/record/components/vehicle-options.vue -->
 2 <script setup>
 3   import { ref } from 'vue'
 4   import { useTaskStore } from '@/stores/task'
 5 ​
 6   const taskStore = useTaskStore()
 7 ​
 8   // 当前被选中选项的索引值
 9   const tabIndex = ref(-1)
10 ​
11   // 接收传入组件的数据
12   const props = defineProps({
13     types: Array,
14     dataKey: String,
15   })
16 ​
17   // 点击选中选项
18   function onOptionSelect(index, id, text) {
19     // 高亮显示选中的选项
20     tabIndex.value = index
21     // 用户选择的是哪个类型
22     console.log(props.dataKey)
23     // 用户选择的是哪个值
24     console.log(text)
25     // 将数据存入 Pinia
26     taskStore.recordData[props.dataKey] = id
27   }
28 </script>
29 <template>
30   <view class="vehicle-options">
31     <view
32       class="option"
33       :class="{ active: tabIndex === index }"
34       v-for="(option, index) in props.types"
35       :key="option.id"
36       @click="onOptionSelect(index, option.id, option.text)"
37     >
38       {{ option.text }}
39     </view>
40   </view>
41 </template>
  1. 是否有车辆故障、交通事故、车辆故障,记录到 Pinia 中

 1 <!-- subpkg_task/record/components/vehicle-violation.vue -->
 2 <script setup>
 3   import { ref } from 'vue'
 4   import vehicleOptions from './vehicle-options'
 5   import { useTaskStore } from '@/stores/task'
 6 ​
 7   const taskStore = useTaskStore()
 8     
 9   // 中间部分代码省略...
10 ​
11   function onRadioChange(ev) {
12     // 展开详细的选项
13     show.value = !!parseInt(ev.detail.value)
14     // 是否有交通违章
15     taskStore.recordData.isBreakRules = show.value
16   }
17 </script>
18 
19 <!-- subpkg_task/record/components/vehicle-breakdown.vue -->
20 <script setup>
21   import { ref } from 'vue'
22   import vehicleOptions from './vehicle-options'
23   import { useTaskStore } from '@/stores/task'
24 ​
25   const taskStore = useTaskStore()
26     
27   // 中间部分代码省略...
28 ​
29   function onRadioChange(ev) {
30     // 展开详细的选项
31     show.value = !!parseInt(ev.detail.value)
32     // 是否有交通违章
33     taskStore.recordData.isFault = show.value
34   }
35 </script>
36 
37 <!-- subpkg_task/record/components/vehicle-accident.vue -->
38 <script setup>
39   import { ref } from 'vue'
40   import vehicleOptions from './vehicle-options'
41   import { useTaskStore } from '@/stores/task'
42 ​
43   const taskStore = useTaskStore()
44     
45   // 中间部分代码省略...
46 ​
47   function onRadioChange(ev) {
48     // 展开详细的选项
49     show.value = !!parseInt(ev.detail.value)
50     // 是否有交通违章
51     taskStore.recordData.isAccident = show.value
52   }
53 </script>
  1. 出车/回车时间记录到 Pinia 中

 1 <!-- subpkg_task/record/index.vue -->
 2 <script setup>
 3   import { ref, computed } from 'vue'
 4   import { onl oad } from '@dcloudio/uni-app'
 5   import { storeToRefs } from 'pinia'
 6   import { useTaskStore } from '@/stores/task'
 7 ​
 8     // 省略中间部分代码
 9 ​
10   // 回车登记的全部数据
11   const { recordData } = storeToRefs(useTaskStore())
12 ​
13   // 获取地址参数
14   onl oad((query) => {
15     // 任务ID
16     recordData.value.id = query.transportTaskId
17     // 发车时间
18     recordData.value.startTime = query.actualDepartureTime
19   })
20 </script>
21 <template>
22   <view class="page-container">
23     <scroll-view class="scroll-view" scroll-y>
24       <view class="scroll-view-wrapper">
25         <uni-list class="base-info">
26           <uni-list-item
27             title="出车时间"
28             show-arrow
29             :right-text="recordData.startTime"
30           />
31           <uni-list-item show-arrow title="回车时间">
32             <template v-slot:footer>
33               <uni-datetime-picker v-model="recordData.endTime">
34                 <view class="picker-value">{{
35                   recordData.endTime || '请选择'
36                 }}</view>
37               </uni-datetime-picker>
38             </template>
39           </uni-list-item>
40         </uni-list>
41                 ...
42       </view>
43     </scroll-view>
44     ...
45   </view>
46 </template>
  1. 将车辆故障描述、交通事故描述及图片存入 Pinia

 1 <!-- subpkg_task/record/components/vehicle-accident.vue -->
 2 <script setup>
 3   // 这里不需要填加新代码...
 4 </script>
 5 ​
 6 <template>
 7   <view class="vehicle-panel">
 8     ...
 9     <view v-show="show" class="vehicle-panel-body">
10       <uni-list>
11         <uni-list-item direction="column" :border="false" title="事故类型">
12           <template v-slot:footer>
13             <vehicle-options data-key="accidentType" :types="types" />
14             <view class="textarea-wrapper">
15               <textarea
16                 v-model="taskStore.recordData.accidentDescription"
17                 class="textarea"
18                 placeholder="请输入事故描述"
19               ></textarea>
20               <view class="words-count">0/50</view>
21             </view>
22           </template>
23         </uni-list-item>
24         <uni-list-item
25           direction="column"
26           :border="false"
27           title="请上传事故现场照片"
28         >
29           <template v-slot:footer>
30             <uni-file-picker
31               v-model="taskStore.recordData.accidentImagesList"
32               file-extname="jpg,webp,gif,png"
33               limit="3"
34             ></uni-file-picker>
35           </template>
36         </uni-list-item>
37       </uni-list>
38     </view>
39   </view>
40 </template>
41 
42 <!-- subpkg_task/record/components/vehicle-breakdown.vue -->
43 <script setup>
44   // 这里不需要填加新代码...
45 </script>
46 ​
47 <template>
48   <view class="vehicle-panel">
49     ...
50     <view v-show="show" class="vehicle-panel-body">
51       <uni-list>
52         <uni-list-item direction="column" :border="false" title="故障类型">
53           <template v-slot:footer>
54             <vehicle-options data-key="faultType" :types="types" />
55             <view class="textarea-wrapper">
56               <textarea
57                 v-model="taskStore.recordData.faultDescription"
58                 class="textarea"
59                 placeholder="请输入故障描述"
60               ></textarea>
61               <view class="words-count">0/50</view>
62             </view>
63           </template>
64         </uni-list-item>
65         <uni-list-item
66           direction="column"
67           :border="false"
68           title="请上传车辆故障照片"
69         >
70           <template v-slot:footer>
71             <uni-file-picker
72               v-model="taskStore.recordData.faultImagesList"
73               file-extname="jpg,webp,gif,png"
74               limit="3"
75             ></uni-file-picker>
76           </template>
77         </uni-list-item>
78       </uni-list>
79     </view>
80   </view>
81 </template>

2.8 提交数据

  到此终于把所需的数处理完整了,调用接口把数据提交即可,接口文档的详细说明在这里。

  1. 封装调用接口的方法

 1 // apis/task.js
 2 // 引入网络请求模块
 3 import { uniFetch } from './uni-fetch'
 4 ​
 5 export default {
 6     // 省略中间部分代码...
 7 ​
 8   /**
 9    * 回车登记
10    * @param {Object} data - 接口数据
11    */
12   record(data) {
13     if (!data.id) return
14     return uniFetch.post('/driver/tasks/truckRegistration', data)
15   },
16 }
17 ​
  1. 调用接口提交数据

 1 <!-- sbupkg_task/record/index.vue -->
 2 <script setup>
 3   import { ref, computed } from 'vue'
 4   import { onl oad } from '@dcloudio/uni-app'
 5   import { storeToRefs } from 'pinia'
 6   import { useTaskStore } from '@/stores/task'
 7   import taskApi from '@/apis/task'
 8     
 9   // 省略中间部分代码...
10 ​
11   // 提交回车登记
12   async function onFormSubmit() {
13     // 过滤掉图片多余的数据,只保留 url
14     const { accidentImagesList, faultImagesList } = recordData.value
15     // 事故照片
16     recordData.value.accidentImagesList = accidentImagesList.map(({ url }) => {
17       return { url }
18     })
19     // 故障照片
20     recordData.value.faultImagesList = faultImagesList.map(({ url }) => {
21       return { url }
22     })
23 ​
24     // 调用接口提交数据
25     const { code } = await taskApi.record(recordData.value)
26     // 检测接口否调用成功
27     if (code !== 200) return uni.utils.toast('回车登记失败!')
28     // 跳转到任务列表
29     uni.reLaunch({ url: '/pages/task/index' })
30   }
31 </script>
32 <template>
33   <view class="page-container">
34     ...
35     <view class="toolbar">
36       <button @click="onFormSubmit" class="button">提交登记</button>
37     </view>
38   </view>
39 </template>

3、已完成

  司机的运输任务完成回成登记后状态会变成 6 即已完成的状态。

3.1 任务列表

  调用接口时传入状态值 6 即可获取已完成的任务列表了

 1 <!-- pages/task/components/complete.vue -->
 2 <script setup>
 3   import { ref, onMounted } from 'vue'
 4   import taskApi from '@/apis/task'
 5 ​
 6   // 已完成任务列表
 7   const completeList = ref([])
 8   // 在途列任务列表是否为空
 9   const isEmpty = ref(false)
10 ​
11   // 生命周期(获取数据)
12   onMounted(() => {
13     getCompleteList()
14   })
15 ​
16   // 在途任务列表
17   async function getCompleteList(page = 1, pageSize = 5) {
18     const { code, data } = await taskApi.list(6, page, pageSize)
19     if (code !== 200) return uni.utils.toast('已完成任务获取失败!')
20     // 渲染数据
21     completeList.value = data.items || []
22     isEmpty.value = completeList.value.length === 0
23   }
24 </script>
25 ​
26 <template>
27   <view class="task-search">
28     <view class="search-bar">
29       <text class="iconfont icon-search"></text>
30       <input class="input" type="text" placeholder="输入任务编号" />
31     </view>
32     <view class="filter-bar">
33       <picker class="picker" mode="date">2023.05.20</picker>
34       <text class="text">至</text>
35       <picker class="picker" mode="date">结束时间</picker>
36       <button disabled class="button">筛选</button>
37     </view>
38   </view>
39   <scroll-view scroll-y refresher-enabled class="scroll-view">
40     <view class="scroll-view-wrapper">
41       <view
42         v-for="complete in completeList"
43         :key="complete.id"
44         class="task-card"
45       >
46         <navigator
47           hover-class="none"
48           :url="`/subpkg_task/detail/index?id=${complete.id}`"
49         >
50           <view class="header">
51             <text class="no">任务编号: {{ complete.transportTaskId }}</text>
52           </view>
53           <view class="body">
54             <view class="timeline">
55               <view class="line">{{ complete.startAddress }}</view>
56               <view class="line">{{ complete.endAddress }}</view>
57             </view>
58           </view>
59         </navigator>
60         <view class="footer flex">
61           <view class="label">提货时间</view>
62           <view class="time">{{ complete.created }}</view>
63         </view>
64       </view>
65       <view v-if="isEmpty" class="task-blank">无完成货物</view>
66     </view>
67   </scroll-view>
68 </template>

3.2 上拉分页

  1. 监听 scrolltolower 事件

 1 <!-- pages/task/components/complete.vue -->
 2 <script setup>
 3   import { ref, onMounted } from 'vue'
 4   import taskApi from '@/apis/task'
 5 ​
 6     // 省略中间部分代码...
 7 ​
 8   // 上拉分页
 9   function onScrollToLower() {
10     // 获取下一页数据
11     getCompleteList()
12   }
13 ​
14   // 任务列表
15   async function getCompleteList(page = 1, pageSize = 5) {
16     // 省略中间部分代码
17   }
18 </script>
19 <template>
20   <scroll-view
21     @scrolltolower="onScrollToLower"
22     class="scroll-view"
23     refresher-enabled
24     scroll-y
25   >
26     ...
27   </scroll-view>
28 </template>
  1. 计算下一页页码

 1 <!-- pages/task/components/complete.vue -->
 2 <script setup>
 3   import { ref, onMounted } from 'vue'
 4   import taskApi from '@/apis/task'
 5 ​
 6     // 省略中间部分代码...
 7   
 8   const nextPage = ref(1)
 9 ​
10     // 省略中间部分代码...
11 ​
12   // 上拉分页
13   function onScrollToLower() {
14     // 获取下一页数据
15     getCompleteList(nextPage.value)
16   }
17 ​
18   // 任务列表
19   async function getCompleteList(page = 1, pageSize = 10) {
20         const { code, data } = await taskApi.list(6, page, pageSize)
21     // 检测接口是否调用成功
22     if (code !== 200) return uni.utils.toast('获取列表失败,稍后重试!')
23     // 渲染数据
24     completeList.value = [...completeList.value, ...(data.items || [])]
25     // 更新下一页页码
26     nextPage.value = ++data.page
27     // 是否为空列表
28     isEmpty.value = completeList.value.length === 0
29   }
30 </script>
31 <template>
32   <scroll-view
33     @scrolltolower="onScrollToLower"
34     class="scroll-view"
35     refresher-enabled
36     scroll-y
37   >
38     ...
39   </scroll-view>
40 </template>

  上述代码中有两点需要注意:

  • 更新页面是根据返回数据中的 page 加 1 的方式处理的

  • 分页请求来的下一页数据需要追加到原数组中,在这里用的 ... 运算符,也可以使用数组的 concat 方法

  1. 判断还有没有更多的数据

 1 <!-- pages/task/components/complete.vue -->
 2 <script setup>
 3   import { ref, onMounted } from 'vue'
 4   import taskApi from '@/apis/task'
 5 ​
 6     // 省略中间部分代码...
 7   
 8   const nextPage = ref(1)
 9   const hasMore = ref(true)
10 ​
11     // 省略中间部分代码...
12 ​
13   // 上拉分页
14   function onScrollToLower() {
15     if(!hasMore.value) return
16     // 获取下一页数据
17     getCompleteList(nextPage.value)
18   }
19 ​
20   // 任务列表
21   async function getCompleteList(page = 1, pageSize = 10) {
22         const { code, data } = await taskApi.list(6, page, pageSize)
23     // 检测接口是否调用成功
24     if (code !== 200) return uni.utils.toast('获取列表失败,稍后重试!')
25     // 渲染数据
26     completeList.value = [...completeList.value, ...(data.items || [])]
27     // 更新下一页页码
28     nextPage.value = ++data.page
29     // 是否为空列表
30     isEmpty.value = completeList.value.length === 0
31     // 是否有更多数据
32     hasMore.value = nextPage.value <= data.pages
33   }
34 </script>
35 <template>
36   <scroll-view
37     @scrolltolower="onScrollToLower"
38     class="scroll-view"
39     refresher-enabled
40     scroll-y
41   >
42     ...
43   </scroll-view>
44 </template>

  上述代码中需要注意判断还有没有更多数据,是根据接口返回数据中的总页码 pages 进行判断的,如果下一页的页码 nextPage 小于等于总页码 data.page 时,表明还有更多的数据,否则没有更多数据了。

3.3 下拉刷新

  1. 监听用户的下拉操作,通过监听 refresherrefresh 来实现

 1 <!-- pages/task/components/complete.vue -->
 2 <script setup>
 3   import { ref, onMounted } from 'vue'
 4   import taskApi from '@/apis/task'
 5   
 6   // 省略了中间部分代码...
 7 ​
 8   // 监听页面是否滚动到底部
 9   function onScrollToLower() {
10     // 省略中间部分代码
11   }
12   
13   // 监听用户的下拉操作
14   async function onScrollViewRefresh() {
15     await getCompleteList()
16   }
17 ​
18   // 获取任务列表
19   async function getCompleteList(page = 1, pageSize = 5) {
20     const { code, data } = await taskApi.list(6, page, pageSize)
21     // 检测接口是否调用成功
22     if (code !== 200) return uni.utils.toast('获取列表失败,稍后重试!')
23     // 页面为 1 时,清空数组
24     if (page === 1) completeList.value = []
25     // 渲染任务列表
26     completeList.value = [...completeList.value, ...(data.items || [])]
27     // 计算下一页页码
28     nextPage.value = ++data.page
29     // 判断列表是否为空
30     isEmpty.value = completeList.value.length === 0
31     // 判断还有没有更多的数据
32     hasMore.value = nextPage.value <= data.pages
33   }
34 </script>
35 <template>
36   <scroll-view
37     @scrolltolower="onScrollToLower"
38     @refresherrefresh="onScrollViewRefresh"
39     scroll-y
40     refresher-enabled
41     class="scroll-view"
42   >
43     ...
44   </scroll-view>
45 </template>

  上述代码中需要关注的两个方面:

  • 刷新请求实际上是重新请求第 1 页的数据

  • 在进行数据渲染时需要清空原列表中的数据

  1. 关闭下拉刷新的动画交互

 1 <!-- pages/task/components/pickup.vue -->
 2 <script setup>
 3   import { ref, onMounted } from 'vue'
 4   import taskApi from '@/apis/task'
 5   
 6   // 省略了中间部分代码...
 7 ​
 8   // 监听页面是否滚动到底部
 9   function onScrollToLower() {
10     // 省略中间部分代码
11   }
12   
13   // 监听用户的下拉操作
14   async function onScrollViewRefresh() {
15     isTriggered.value = true
16     await getCompleteList()
17     // 关闭动画交互
18     isTriggered.value = false
19   }
20 ​
21   // 获取任务列表
22   async function getCompleteList(page = 1, pageSize = 5) {
23     // 省略中间部分代码...
24   }
25 </script>
26 <template>
27   <scroll-view
28     @scrolltolower="onScrollToLower"
29     @refresherrefresh="onScrollViewRefresh"
30     :refresher-triggered="isTriggered"
31     scroll-y
32     refresher-enabled
33     class="scroll-view"
34   >
35     ...
36   </scroll-view>
37 </template>

  上述代码中要注意:

  • scroll-view 下拉刷新的动画交互需要通过 refresher-triggiered 来打开或关闭,如果值为 true 时打开,值为 false 时关闭

  • 需要为调用方法指定 async/await 在请求结束后再关闭动画交互

 

标签:uniapp,06,...,text,value,import,ref,id,神领
From: https://www.cnblogs.com/wang1001/p/18152039

相关文章

  • 前端【uniapp】03-uniapp【练习项目 · 神领物流】
    uni-app(神领物流)项目实战学习目标:能够对Pinia进行初始化操作掌握创建Store及数据操作的步骤能够对Pinia数据进行持久化的处理掌握uniForm表单验证的使用方法能够根据业务需求配置请求/响应拦截器一、【神领物流】项目启动本节的主要任务是获取项......
  • 前端【uniapp】02-uniapp【全局文件】【组件【内置、扩展】】【声明周期】【API调用】
    一、uni-app基础知识uni-app是组合了Vue和微信小程序的相关技术知识,要求大家同时俱备Vue和原生小程序的开发基础。1、全局文件在小程序中有全局样式、全局配置等全局性的设置,为此在uni-app中也有一些与之相对应的全局性的文件。uni.scssuni-app项目在运......
  • docker - [06] 安装部署Tomcat
    题记部分   一、官方测试镜像官方文档给出以下命令,一般用来测试,用完即删,下载并运行镜像,退出镜像就会自动删除镜像?亲测不会自动删除dockerrun-it--rmtomcat:9.0使用快捷键:Ctrl+P+Q可以让其在后台运行(这里执行Ctrl+C之后,dockerimages还是有tomcat镜像) ......
  • pycharm破解安装激活2023-06最新教程(附破解工具及激活码)
    pycharm破解安装激活2023-06最新教程(附破解工具及激活码) 先去官网安装pycharm:https://www.jetbrains.com.cn/pycharm/download/#section=windows我这里下载的是最新版本2023.1.2,2021年以上的版本都支持此教程破解。先讲安装再讲破解。  点next 选好路径然后nex......
  • 洛谷题单指南-动态规划1-P1064 [NOIP2006 提高组] 金明的预算方案
    原题链接:https://www.luogu.com.cn/problem/P1064题意解读:用固定钱数购买最大价值的物品。解题思路:背包问题,背包问题里的体积相当于物品价格,价值相当于价格*重要度物品分为主件、附件,主件最多有0/1/2个附件,要选附件必须选相应主件,因此在递推计算dp[j]总价格j能购买的最大价......
  • MySQL-06.索引的数据结构
    1.为什么使用索引索引是存储引擎用于快速找到数据记录的一种数据结构,就好比一本书的目录部分,通过目录中找到对应文章的页码,便可快速定位到需要的文章。MySQL中的索引也是一样的道理,进行数据查找时,首先查看查询条件是否命中某条索引,符合则通过索引查找相关数据,如果不符合则需要全......
  • CF1067E Random Forest Rank 题解
    这道题涉及了组合分析和概率。本质上,当以一定的概率从给定的树中删除边时,您需要找到结果林的邻接矩阵的期望秩。要解决这个问题,可以使用动态规划。我们用\(f(u,v)\)表示当删除边\((u,v)\)时,由以顶点\(v\)为根的子树中的顶点形成的林的期望秩。这里,\(u\)和\(v\)是树中的......
  • Random 项目总结 -06 定时器、 随机数,截图,生成WORD报告 (result完整)
    usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Drawing.Imaging;usingSystem.Linq;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.Xml;usingMsword=Microsoft.Office.......
  • P9745 「KDOI-06-S」树上异或
    P9745「KDOI-06-S」树上异或位运算trick+树形dp看到题目中贡献的计算,可以想到乘法分配律,也就是一个连通块的乘积可以直接乘在当前所有方案的权值之和上。可以考虑特殊性质:链。那么树的问题就变成了序列问题。容易设\(f_i\)表示\(i\)以前的节点的所有断边方案权值和。转移......
  • uniapp安卓在线更新版本
    实现逻辑通过获取线上的版本号和app的版本号进行对比查看是不是最新版—app版本号小于线上版本号则不是最新版提示更新模拟检测更新请求起一个服务,也就是检测更新的接口返回值为最新版本号和最新版wgt文件下载地址,例:{  "code":0,  "msg":"success",  ......