|
|
@@ -8,7 +8,7 @@
|
|
|
:bounces="false"
|
|
|
>
|
|
|
<view class="task-form__content" :style="contentStyle">
|
|
|
- <view class="workbench-notice" v-if="showNotice">
|
|
|
+ <view v-if="showNotice" class="workbench-notice">
|
|
|
<wd-notice-bar
|
|
|
:text="noticeText"
|
|
|
prefix="warn-bold"
|
|
|
@@ -20,111 +20,116 @@
|
|
|
</view>
|
|
|
|
|
|
<view class="task-form-fields">
|
|
|
- <view class="task-form-field" v-for="item in taskFieldConfigList" :key="item.id">
|
|
|
- <template v-if="isSingleSelect(item.taskFiledType)">
|
|
|
+ <template v-for="item in taskFieldConfigList" :key="item.id">
|
|
|
+ <view v-if="form.value[item.id]" class="task-form-field">
|
|
|
<SingleSelect
|
|
|
- :taskFieldConfig="item"
|
|
|
- :taskFieldDict="taskFieldDict"
|
|
|
+ v-if="isSingleSelect(item.taskFiledType)"
|
|
|
v-model:label="form.value[item.id].label"
|
|
|
v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
+ :before-open="() => handleSingleSelectBeforeOpen(item)"
|
|
|
+ @change="handleSingleSelectChange(item, $event)"
|
|
|
/>
|
|
|
- </template>
|
|
|
|
|
|
- <template v-else-if="isTextInput(item.taskFiledType)">
|
|
|
<SingleText
|
|
|
- :taskFieldConfig="item"
|
|
|
- :readonly="item.taskFiledType === 'readonlytext'"
|
|
|
+ v-else-if="isTextInput(item.taskFiledType)"
|
|
|
v-model:label="form.value[item.id].label"
|
|
|
v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
+ :readonly="isReadonlyText(item.taskFiledType)"
|
|
|
/>
|
|
|
- </template>
|
|
|
|
|
|
- <template v-else-if="isDateTime(item.taskFiledType)">
|
|
|
<DateTimePicker
|
|
|
- :taskFieldConfig="item"
|
|
|
+ v-else-if="isDateTime(item.taskFiledType)"
|
|
|
v-model:label="form.value[item.id].label"
|
|
|
v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
/>
|
|
|
- </template>
|
|
|
|
|
|
- <template v-else-if="isLocation(item.taskFiledType)">
|
|
|
<TaskLocation
|
|
|
- :taskFieldConfig="item"
|
|
|
+ v-else-if="isLocation(item.taskFiledType)"
|
|
|
v-model:label="form.value[item.id].label"
|
|
|
v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
/>
|
|
|
- </template>
|
|
|
|
|
|
- <template v-else-if="isImgUpload(item.taskFiledType)">
|
|
|
- <view class="line" />
|
|
|
- <ImgUpload
|
|
|
- :taskFieldConfig="item"
|
|
|
- v-model:label="form.value[item.id].label"
|
|
|
- v-model:value="form.value[item.id].value"
|
|
|
- />
|
|
|
- </template>
|
|
|
+ <template v-else-if="isImgUpload(item.taskFiledType)">
|
|
|
+ <view class="line" />
|
|
|
|
|
|
- <template v-else-if="isSign(item.taskFiledType)">
|
|
|
- <view class="line" />
|
|
|
- <Sign
|
|
|
- :taskFieldConfig="item"
|
|
|
- v-model:label="form.value[item.id].label"
|
|
|
- v-model:value="form.value[item.id].value"
|
|
|
- />
|
|
|
- </template>
|
|
|
+ <ImgUpload
|
|
|
+ v-model:label="form.value[item.id].label"
|
|
|
+ v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-else-if="isSign(item.taskFiledType)">
|
|
|
+ <view class="line" />
|
|
|
+
|
|
|
+ <Sign
|
|
|
+ v-model:label="form.value[item.id].label"
|
|
|
+ v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
|
|
|
- <template v-else-if="isMultipleSelect(item.taskFiledType)">
|
|
|
<MultipleSelect
|
|
|
- :taskFieldConfig="item"
|
|
|
- :taskFieldDict="taskFieldDict"
|
|
|
+ v-else-if="isMultipleSelect(item.taskFiledType)"
|
|
|
v-model:label="form.value[item.id].label"
|
|
|
v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
+ :before-open="() => handleMultipleSelectBeforeOpen(item)"
|
|
|
/>
|
|
|
- </template>
|
|
|
|
|
|
- <template v-else-if="isInputAutoSelect(item.taskFiledType)">
|
|
|
<InputAutoSelect
|
|
|
- :taskFieldConfig="item"
|
|
|
+ v-else-if="isInputAutoSelect(item.taskFiledType)"
|
|
|
v-model:label="form.value[item.id].label"
|
|
|
v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
/>
|
|
|
- </template>
|
|
|
|
|
|
- <template v-else-if="isDateTimeRange(item.taskFiledType)">
|
|
|
<DataTimeRange
|
|
|
- :taskFieldConfig="item"
|
|
|
+ v-else-if="isDateTimeRange(item.taskFiledType)"
|
|
|
v-model:label="form.value[item.id].label"
|
|
|
v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
/>
|
|
|
- </template>
|
|
|
|
|
|
- <template v-else-if="isLongText(item.taskFiledType)">
|
|
|
- <view class="line" />
|
|
|
- <LongText
|
|
|
- :taskFieldConfig="item"
|
|
|
- v-model:label="form.value[item.id].label"
|
|
|
- v-model:value="form.value[item.id].value"
|
|
|
- />
|
|
|
- <view class="line" />
|
|
|
- </template>
|
|
|
+ <template v-else-if="isLongText(item.taskFiledType)">
|
|
|
+ <view class="line" />
|
|
|
+
|
|
|
+ <LongText
|
|
|
+ v-model:label="form.value[item.id].label"
|
|
|
+ v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
+ />
|
|
|
+
|
|
|
+ <view class="line" />
|
|
|
+ </template>
|
|
|
|
|
|
- <template v-else-if="isArea(item.taskFiledType)">
|
|
|
<Area
|
|
|
- :taskFieldConfig="item"
|
|
|
+ v-else-if="isArea(item.taskFiledType)"
|
|
|
v-model:label="form.value[item.id].label"
|
|
|
v-model:value="form.value[item.id].value"
|
|
|
+ :task-field-config="item"
|
|
|
+ :select-level="selectLevel"
|
|
|
/>
|
|
|
- </template>
|
|
|
- </view>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
</view>
|
|
|
</view>
|
|
|
</scroll-view>
|
|
|
|
|
|
- <view class="task-form-footer" :style="footerStyle">
|
|
|
+ <DuplicateImageDialog
|
|
|
+ v-model="duplicateImageVisible"
|
|
|
+ :images="duplicateImageList"
|
|
|
+ @confirm="clearDuplicateImages"
|
|
|
+ />
|
|
|
+
|
|
|
+ <view v-if="taskFieldConfigList.length" class="task-form-footer" :style="footerStyle">
|
|
|
<button
|
|
|
class="task-form-footer__button task-form-footer__button--save"
|
|
|
hover-class="task-form-footer__button--hover"
|
|
|
- :disabled="actionLoading !== null"
|
|
|
@click="handleSave"
|
|
|
>
|
|
|
保存
|
|
|
@@ -133,7 +138,6 @@
|
|
|
<button
|
|
|
class="task-form-footer__button task-form-footer__button--submit"
|
|
|
hover-class="task-form-footer__button--hover"
|
|
|
- :disabled="actionLoading !== null"
|
|
|
@click="handleSubmit"
|
|
|
>
|
|
|
提交
|
|
|
@@ -147,12 +151,10 @@ import { ref } from 'vue'
|
|
|
|
|
|
import { onLoad } from '@dcloudio/uni-app'
|
|
|
|
|
|
-import { saveTaskContentApi } from '@/services/modules/task/taskFrom'
|
|
|
-import type { SaveTaskContentBody } from '@/services/modules/task/taskFrom/type'
|
|
|
-
|
|
|
import Area from './components/Area.vue'
|
|
|
import DataTimeRange from './components/DataTimeRange.vue'
|
|
|
import DateTimePicker from './components/DateTimePicker.vue'
|
|
|
+import DuplicateImageDialog from './components/DuplicateImageDialog.vue'
|
|
|
import ImgUpload from './components/ImgUpload.vue'
|
|
|
import InputAutoSelect from './components/InputAutoSelect.vue'
|
|
|
import LongText from './components/LongText.vue'
|
|
|
@@ -161,138 +163,89 @@ import Sign from './components/Sign.vue'
|
|
|
import SingleSelect from './components/SingleSelect.vue'
|
|
|
import SingleText from './components/SingleText.vue'
|
|
|
import TaskLocation from './components/TaskLocation.vue'
|
|
|
-import { useNavigation } from './composables/useNavigation'
|
|
|
+import { useTaskFieldType } from './composables/useTaskFieldType'
|
|
|
import { useTaskForm } from './composables/useTaskForm'
|
|
|
+import { useTaskFormAction } from './composables/useTaskFormAction'
|
|
|
+import { useTaskFormPageFeatures } from './composables/useTaskFormPageFeatures'
|
|
|
import { useTaskFormSafeArea } from './composables/useTaskFormSafeArea'
|
|
|
-import { useTaskNotice } from './composables/useTaskNotice'
|
|
|
+import { useTaskSelectHandlers } from './composables/useTaskSelectHandlers'
|
|
|
|
|
|
-type PageLoadOptions = {
|
|
|
+interface PageLoadOptions {
|
|
|
+ taskTypeId?: string
|
|
|
taskTitle?: string
|
|
|
- taskId?: string
|
|
|
}
|
|
|
|
|
|
-type FormAction = 'save' | 'submit'
|
|
|
+const taskTypeId = ref('')
|
|
|
+
|
|
|
+const { form, taskFieldConfigList, loadTaskForm } = useTaskForm()
|
|
|
+
|
|
|
+const { handleSingleSelectBeforeOpen, handleSingleSelectChange, handleMultipleSelectBeforeOpen } =
|
|
|
+ useTaskSelectHandlers({
|
|
|
+ taskTypeId,
|
|
|
+ form,
|
|
|
+ taskFieldConfigList,
|
|
|
+ })
|
|
|
+
|
|
|
+const {
|
|
|
+ duplicateImageVisible,
|
|
|
+ duplicateImageList,
|
|
|
+ clearDuplicateImages,
|
|
|
+ handleSave,
|
|
|
+ handleSubmit,
|
|
|
+} = useTaskFormAction({
|
|
|
+ taskTypeId,
|
|
|
+ form,
|
|
|
+ taskFieldConfigList,
|
|
|
+})
|
|
|
+const {
|
|
|
+ isSingleSelect,
|
|
|
+ isTextInput,
|
|
|
+ isReadonlyText,
|
|
|
+ isDateTime,
|
|
|
+ isLocation,
|
|
|
+ isImgUpload,
|
|
|
+ isSign,
|
|
|
+ isMultipleSelect,
|
|
|
+ isInputAutoSelect,
|
|
|
+ isDateTimeRange,
|
|
|
+ isLongText,
|
|
|
+ isArea,
|
|
|
+} = useTaskFieldType()
|
|
|
+
|
|
|
+const { showNotice, noticeText, selectLevel, initializeTaskFormPage } = useTaskFormPageFeatures()
|
|
|
|
|
|
-const { setNavigationTitle } = useNavigation()
|
|
|
-const { showNotice, noticeText, setNotice } = useTaskNotice()
|
|
|
-const { form, taskFieldConfigList, taskFieldDict, loadTaskForm } = useTaskForm()
|
|
|
const { contentStyle, footerStyle, initSafeArea } = useTaskFormSafeArea()
|
|
|
|
|
|
-const actionLoading = ref<FormAction | null>(null)
|
|
|
-
|
|
|
-const isSingleSelect = (taskFiledType: string) => {
|
|
|
- return ['domain', 'select'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isTextInput = (taskFiledType: string) => {
|
|
|
- return ['text', 'readonlytext', 'money', 'number'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isDateTime = (taskFiledType: string) => {
|
|
|
- return ['datetime'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isLocation = (taskFiledType: string) => {
|
|
|
- return ['map', 'mapwithimg', 'currPosi'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isImgUpload = (taskFiledType: string) => {
|
|
|
- return ['img'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isSign = (taskFiledType: string) => {
|
|
|
- return ['sign'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isMultipleSelect = (taskFiledType: string) => {
|
|
|
- return ['multiple_select'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isInputAutoSelect = (taskFiledType: string) => {
|
|
|
- return ['inputautoselect'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isDateTimeRange = (taskFiledType: string) => {
|
|
|
- return ['datatimerange'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isLongText = (taskFiledType: string) => {
|
|
|
- return ['longtext'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const isArea = (taskFiledType: string) => {
|
|
|
- return ['area'].includes(taskFiledType)
|
|
|
-}
|
|
|
-
|
|
|
-const handleSave = () => {
|
|
|
- void handleFormAction('save')
|
|
|
-}
|
|
|
-
|
|
|
-const handleSubmit = () => {
|
|
|
- void handleFormAction('submit')
|
|
|
-}
|
|
|
-
|
|
|
-const buildSubmitPayload = (): SaveTaskContentBody => {
|
|
|
- const payload: SaveTaskContentBody = {}
|
|
|
-
|
|
|
- for (const field of taskFieldConfigList.value) {
|
|
|
- const fieldValue = form.value.value[String(field.id)]
|
|
|
-
|
|
|
- payload[field.taskFiledValue] = {
|
|
|
- seq: field.seq ?? 0,
|
|
|
- ...(field.isMustfill === '1' ? { required: true } : {}),
|
|
|
- items: [
|
|
|
- {
|
|
|
- label: String(fieldValue?.label ?? ''),
|
|
|
- type: field.taskFiledType,
|
|
|
- value: String(fieldValue?.value ?? ''),
|
|
|
- },
|
|
|
- ],
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return payload
|
|
|
-}
|
|
|
-
|
|
|
-const handleFormAction = async (action: FormAction) => {
|
|
|
- if (actionLoading.value !== null) return
|
|
|
-
|
|
|
- actionLoading.value = action
|
|
|
+const decodeRouteParam = (value?: string): string => {
|
|
|
+ if (!value) return ''
|
|
|
|
|
|
try {
|
|
|
- console.log(`${action}: form.value`, form.value)
|
|
|
-
|
|
|
- const payload = buildSubmitPayload()
|
|
|
- console.log('payload', payload)
|
|
|
-
|
|
|
- if (action === 'save') {
|
|
|
- // TODO: 调保存接口
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- const saveTaskContentQuery = {
|
|
|
- taskTypeId: '46',
|
|
|
- packageId: '8612',
|
|
|
- }
|
|
|
- const res = await saveTaskContentApi(saveTaskContentQuery, payload)
|
|
|
- console.log('res', res)
|
|
|
-
|
|
|
- // TODO: 调提交接口
|
|
|
- } finally {
|
|
|
- actionLoading.value = null
|
|
|
+ return decodeURIComponent(value)
|
|
|
+ } catch {
|
|
|
+ return value
|
|
|
}
|
|
|
}
|
|
|
|
|
|
onLoad(async (options: PageLoadOptions = {}) => {
|
|
|
initSafeArea()
|
|
|
|
|
|
- setNavigationTitle(options.taskTitle)
|
|
|
+ taskTypeId.value = options.taskTypeId?.trim() ?? ''
|
|
|
+
|
|
|
+ if (!taskTypeId.value) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '缺少 taskTypeId',
|
|
|
+ icon: 'none',
|
|
|
+ })
|
|
|
|
|
|
- const taskId = options.taskId ?? ''
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- setNotice(taskId)
|
|
|
+ initializeTaskFormPage({
|
|
|
+ taskTypeId: taskTypeId.value,
|
|
|
+ taskTitle: decodeRouteParam(options.taskTitle),
|
|
|
+ })
|
|
|
|
|
|
- await loadTaskForm(taskId)
|
|
|
+ await loadTaskForm(taskTypeId.value)
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
@@ -339,10 +292,10 @@ onLoad(async (options: PageLoadOptions = {}) => {
|
|
|
position: fixed;
|
|
|
right: 0;
|
|
|
left: 0;
|
|
|
- z-index: 99;
|
|
|
+ z-index: 9;
|
|
|
display: flex;
|
|
|
gap: 16rpx;
|
|
|
- padding: 20rpx 28rpx 20rpx;
|
|
|
+ padding: 20rpx 28rpx;
|
|
|
background: #fff;
|
|
|
box-sizing: border-box;
|
|
|
box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
|
|
|
@@ -356,19 +309,13 @@ onLoad(async (options: PageLoadOptions = {}) => {
|
|
|
border: 0;
|
|
|
border-radius: 12rpx;
|
|
|
font-size: 32rpx;
|
|
|
- font-weight: 400;
|
|
|
line-height: 88rpx;
|
|
|
- box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
.task-form-footer__button::after {
|
|
|
border: 0;
|
|
|
}
|
|
|
|
|
|
-.task-form-footer__button[disabled] {
|
|
|
- opacity: 0.6;
|
|
|
-}
|
|
|
-
|
|
|
.task-form-footer__button--hover {
|
|
|
opacity: 0.85;
|
|
|
}
|