todo-search-form.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <template>
  2. <!-- 搜索框入口 -->
  3. <wd-search
  4. :placeholder="searchPlaceholder"
  5. :hide-cancel="true"
  6. disabled
  7. @click="visible = true"
  8. />
  9. <!-- 搜索弹窗 -->
  10. <wd-popup
  11. v-model="visible"
  12. position="top"
  13. custom-style="border-radius: 0 0 24rpx 24rpx;"
  14. safe-area-inset-top
  15. @close="visible = false"
  16. >
  17. <view class="p-32rpx">
  18. <view class="mb-24rpx text-32rpx text-[#333] font-semibold">
  19. 搜索任务
  20. </view>
  21. <view class="mb-24rpx">
  22. <view class="mb-12rpx text-28rpx text-[#666]">
  23. 任务名称
  24. </view>
  25. <wd-input
  26. v-model="formData.name"
  27. placeholder="请输入任务名称"
  28. clearable
  29. />
  30. </view>
  31. <view v-if="processDefinitionList.length > 0" class="mb-24rpx">
  32. <view class="mb-12rpx text-28rpx text-[#666]">
  33. 所属流程
  34. </view>
  35. <wd-picker
  36. v-model="formData.processDefinitionKey"
  37. :columns="processDefinitionList"
  38. label-key="name"
  39. value-key="key"
  40. label=""
  41. />
  42. </view>
  43. <view v-if="categoryList.length > 0" class="mb-24rpx">
  44. <view class="mb-12rpx text-28rpx text-[#666]">
  45. 流程分类
  46. </view>
  47. <wd-picker
  48. v-model="formData.category"
  49. :columns="categoryList"
  50. label-key="name"
  51. value-key="code"
  52. label=""
  53. />
  54. </view>
  55. <view class="mb-24rpx">
  56. <view class="mb-12rpx text-28rpx text-[#666]">
  57. 流程状态
  58. </view>
  59. <wd-radio-group v-model="formData.status" shape="button">
  60. <wd-radio :value="-1">
  61. 全部
  62. </wd-radio>
  63. <wd-radio v-for="dict in getIntDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS)" :key="dict.value" :value="dict.value">
  64. {{ dict.label }}
  65. </wd-radio>
  66. </wd-radio-group>
  67. </view>
  68. <!-- DONE @AI:时时间范围,参考下 /Users/yunai/Java/yudao-ui-admin-uniapp-next/src/pages/message/components/search-form.vue -->
  69. <view class="mb-32rpx">
  70. <view class="mb-12rpx text-28rpx text-[#666]">
  71. 发起时间
  72. </view>
  73. <view class="flex items-center gap-16rpx">
  74. <view class="flex-1" @click="visibleCreateTime[0] = true">
  75. <view
  76. class="h-72rpx flex items-center justify-center rounded-8rpx bg-[#f5f5f5] px-24rpx text-28rpx"
  77. >
  78. {{ formatDate(formData.createTime?.[0]) || '开始日期' }}
  79. </view>
  80. </view>
  81. <text class="text-28rpx text-[#999]">至</text>
  82. <view class="flex-1" @click="visibleCreateTime[1] = true">
  83. <view
  84. class="h-72rpx flex items-center justify-center rounded-8rpx bg-[#f5f5f5] px-24rpx text-28rpx"
  85. >
  86. {{ formatDate(formData.createTime?.[1]) || '结束日期' }}
  87. </view>
  88. </view>
  89. </view>
  90. <wd-datetime-picker-view
  91. v-if="visibleCreateTime[0]"
  92. v-model="tempCreateTime[0]"
  93. type="date"
  94. :columns-height="200"
  95. />
  96. <view v-if="visibleCreateTime[0]" class="mt-16rpx flex justify-end gap-16rpx">
  97. <wd-button size="small" plain @click="handleCreateTime0Cancel">
  98. 取消
  99. </wd-button>
  100. <wd-button size="small" type="primary" @click="handleCreateTime0Confirm">
  101. 确定
  102. </wd-button>
  103. </view>
  104. <wd-datetime-picker-view
  105. v-if="visibleCreateTime[1]"
  106. v-model="tempCreateTime[1]"
  107. type="date"
  108. :columns-height="200"
  109. />
  110. <view v-if="visibleCreateTime[1]" class="mt-16rpx flex justify-end gap-16rpx">
  111. <wd-button size="small" plain @click="handleCreateTime1Cancel">
  112. 取消
  113. </wd-button>
  114. <wd-button size="small" type="primary" @click="handleCreateTime1Confirm">
  115. 确定
  116. </wd-button>
  117. </view>
  118. </view>
  119. <view class="w-full flex justify-center gap-24rpx">
  120. <wd-button class="flex-1" plain @click="handleReset">
  121. 重置
  122. </wd-button>
  123. <wd-button class="flex-1" type="primary" @click="handleSearch">
  124. 搜索
  125. </wd-button>
  126. </view>
  127. </view>
  128. </wd-popup>
  129. </template>
  130. <script lang="ts" setup>
  131. import type { Category } from '@/api/bpm/category'
  132. import type { ProcessDefinition } from '@/api/bpm/definition'
  133. import { computed, onMounted, reactive, ref, watch } from 'vue'
  134. import { getCategorySimpleList } from '@/api/bpm/category'
  135. import { getProcessDefinitionList } from '@/api/bpm/definition'
  136. import { getDictLabel, getIntDictOptions } from '@/hooks/useDict'
  137. import { DICT_TYPE } from '@/utils/constants'
  138. import { formatDate } from '@/utils/date'
  139. /** 搜索表单数据 */
  140. export interface TodoSearchFormData {
  141. name?: string
  142. processDefinitionKey?: string
  143. category?: string
  144. status: number // -1 表示全部
  145. createTime?: [number | undefined, number | undefined]
  146. }
  147. const props = defineProps<{
  148. searchParams?: Partial<TodoSearchFormData>
  149. }>()
  150. const emit = defineEmits<{
  151. search: [data: TodoSearchFormData]
  152. reset: []
  153. }>()
  154. const visible = ref(false)
  155. const formData = reactive<TodoSearchFormData>({
  156. name: undefined,
  157. processDefinitionKey: undefined,
  158. category: undefined,
  159. status: -1,
  160. createTime: [undefined, undefined],
  161. })
  162. /** 搜索条件 placeholder 拼接 */
  163. const searchPlaceholder = computed(() => {
  164. const conditions: string[] = []
  165. if (props.searchParams?.name) {
  166. conditions.push(`名称:${props.searchParams.name}`)
  167. }
  168. if (props.searchParams?.status !== undefined && props.searchParams.status !== -1) {
  169. conditions.push(`状态:${getDictLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS, props.searchParams.status)}`)
  170. }
  171. if (props.searchParams?.createTime?.[0] && props.searchParams?.createTime?.[1]) {
  172. conditions.push(`时间:${formatDate(props.searchParams.createTime[0])}~${formatDate(props.searchParams.createTime[1])}`)
  173. }
  174. return conditions.length > 0 ? conditions.join(' | ') : '搜索待办任务'
  175. })
  176. const categoryList = ref<Category[]>([])
  177. const processDefinitionList = ref<ProcessDefinition[]>([])
  178. // 时间选择器状态
  179. const visibleCreateTime = ref<[boolean, boolean]>([false, false])
  180. const tempCreateTime = ref<[number, number]>([Date.now(), Date.now()])
  181. /** 创建时间[0]确认 */
  182. function handleCreateTime0Confirm() {
  183. formData.createTime = [tempCreateTime.value[0], formData.createTime?.[1]]
  184. visibleCreateTime.value[0] = false
  185. }
  186. /** 创建时间[0]取消 */
  187. function handleCreateTime0Cancel() {
  188. visibleCreateTime.value[0] = false
  189. }
  190. /** 创建时间[1]确认 */
  191. function handleCreateTime1Confirm() {
  192. formData.createTime = [formData.createTime?.[0], tempCreateTime.value[1]]
  193. visibleCreateTime.value[1] = false
  194. }
  195. /** 创建时间[1]取消 */
  196. function handleCreateTime1Cancel() {
  197. visibleCreateTime.value[1] = false
  198. }
  199. /** 获取流程分类列表 */
  200. async function getCategoryList() {
  201. try {
  202. categoryList.value = await getCategorySimpleList()
  203. } catch (error) {
  204. console.error('获取流程分类失败:', error)
  205. }
  206. }
  207. /** 获取流程定义列表 */
  208. async function getProcessDefinitions() {
  209. try {
  210. processDefinitionList.value = await getProcessDefinitionList({ suspensionState: 1 })
  211. } catch (error) {
  212. console.error('获取流程定义失败:', error)
  213. }
  214. }
  215. /** 监听弹窗打开,同步外部参数 */
  216. watch(visible, (val) => {
  217. if (val && props.searchParams) {
  218. formData.name = props.searchParams.name
  219. formData.processDefinitionKey = props.searchParams.processDefinitionKey
  220. formData.category = props.searchParams.category
  221. formData.status = props.searchParams.status ?? -1
  222. formData.createTime = props.searchParams.createTime ?? [undefined, undefined]
  223. }
  224. })
  225. /** 搜索 */
  226. function handleSearch() {
  227. visible.value = false
  228. emit('search', { ...formData })
  229. }
  230. /** 重置 */
  231. function handleReset() {
  232. formData.name = undefined
  233. formData.processDefinitionKey = undefined
  234. formData.category = undefined
  235. formData.status = -1
  236. formData.createTime = [undefined, undefined]
  237. visible.value = false
  238. emit('reset')
  239. }
  240. /** 初始化 */
  241. onMounted(() => {
  242. getCategoryList()
  243. getProcessDefinitions()
  244. })
  245. </script>