index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. <template>
  2. <el-dialog v-model="props.visible" width="800px" :show-close="false" :close-on-click-modal="false" top="10vh">
  3. <template #header="{ titleId, titleClass }">
  4. <div class="flex justify-between items-center border-b pb-3">
  5. <h4 :id="titleId" :class="titleClass">{{ title || "新建任务" }}</h4>
  6. <div>
  7. <el-button v-if="!editForm" type="primary" :loading="['2'].includes(props.saveLoading)"
  8. @click="submitForm(formRef, true)">保存并新建</el-button>
  9. <el-button type="primary" :loading="['2'].includes(props.saveLoading)"
  10. @click="submitForm(formRef, false)">保存</el-button>
  11. <el-button @click="closeVisible()">取消</el-button>
  12. </div>
  13. </div>
  14. </template>
  15. <div class="h-[55vh] overflow-y-auto scroll-bar mt-5">
  16. <el-form ref="formRef" :model="form" label-width="7em" :rules="rules" class="flex flex-wrap form">
  17. <el-form-item label="任务名称:" prop="taskName" required>
  18. <el-input v-model="form.taskName" type="textarea" placeholder="请输入任务名称" clearable maxlength="100"
  19. show-word-limit :disabled="disabledList && disabledList.includes('taskName')" />
  20. </el-form-item>
  21. <el-form-item prop="priority" label="优先级:" required>
  22. <el-select v-model="form.priority" placeholder="请选择" clearable
  23. :disabled="disabledList && disabledList.includes('priority')">
  24. <el-option v-for="item in PRIORITY " :key="item.value" :value="item.value" :label="item.label" />
  25. </el-select>
  26. </el-form-item>
  27. <el-form-item :label="form.taskType">
  28. <template #label>
  29. <el-select v-model="form.taskType" class="border resetSelect" style="width: 100px" @change="changeTaskType"
  30. :disabled="disabledList && disabledList.includes('taskType')">
  31. <el-option v-for="item in TASK_TYPE" :key="item.value" :value="item.value" :label="item.label" />
  32. </el-select>
  33. </template>
  34. <template v-for="item in TASK_TYPE_FIELD">
  35. <el-select v-model="form[item.field]" v-if="form.taskType == item.type" placeholder="请选择" clearable
  36. filterable :disabled="disabledList && disabledList.includes(item.field)">
  37. <el-option v-for="v in taskTypeValueData" :key="v.id" :value="v[item.valueIndex]"
  38. :label="v[item.labelIndex]" />
  39. </el-select>
  40. </template>
  41. </el-form-item>
  42. <el-form-item label="联系人:" v-if="TASK_TYPE.find(v => v.value == (form.taskType || '1'))?.show">
  43. <el-select v-model="form.contactsId" placeholder="请选择" clearable filterable
  44. :disabled="disabledList && disabledList.includes('contactsId')">
  45. <el-option v-for="item in contactValueData" :key="item.id" :value="item.id" :label="item.name" />
  46. </el-select>
  47. </el-form-item>
  48. <el-form-item label="执行人:">
  49. <el-select v-model="form.executorId" placeholder="请选择" clearable multiple filterable
  50. :disabled="disabledList && disabledList.includes('executorId')">
  51. <el-option v-for="item in executorValueData" :key="item.id" :value="item.id" :label="item.name" />
  52. </el-select>
  53. </el-form-item>
  54. <el-form-item label="重复提醒:">
  55. <el-switch v-model="form.isRepeat" :active-value="1" :inactive-value="0" @change="changeRepeat" />
  56. </el-form-item>
  57. <template v-if="form.isRepeat === 1">
  58. <el-form-item label="重复类型:">
  59. <el-select v-model="form.repeatType" placeholder="请选择" @change="changeRepeatType">
  60. <el-option v-for="item in REPEAT_TYPE" :key="item.value" :value="item.value" :label="item.label" />
  61. </el-select>
  62. </el-form-item>
  63. <template v-if="[0, 1, 2, 3].includes(form.repeatType)">
  64. <el-form-item label="每:" v-if="form.repeatType == 3">
  65. <el-input-number v-model="form.repeatDesignSameday" controls-position="right" :min="1" />天
  66. </el-form-item>
  67. <el-form-item label="结束:">
  68. <el-radio-group v-model="form.endType" @change="changeEndType">
  69. <el-radio :label="1" class="w-full">永不</el-radio>
  70. <el-radio :label="2" class="w-full mb-3"><el-input-number v-model="form.repeatEndCount" :min="1"
  71. controls-position="right" :disabled="form.endType != 2" />
  72. 次以后
  73. </el-radio>
  74. <el-radio :label="3" class="w-full">
  75. <el-date-picker v-model="form.repeatEndDate" type="date" placeholder="选择日期" style="width:65%"
  76. :disabled-date="(value: Date) => (new Date() > new Date(value))" value-format="YYYY-MM-DD"
  77. :disabled="form.endType != 3" />
  78. 以后
  79. </el-radio>
  80. </el-radio-group>
  81. </el-form-item>
  82. </template>
  83. <template v-if="[4].includes(form.repeatType)">
  84. <el-form-item v-for="(v, i) in customeDate" class="flex justify-between items-center customeDate">
  85. <div>
  86. 第{{ i + 1 }}次重复在
  87. <el-input-number :model-value="Number(v)" controls-position="right" @change="changeDate(i, $event)"
  88. :min="1" />
  89. 天后
  90. </div>
  91. <div>
  92. <el-icon size="24" @click="deleteCustomeDateItem(i)" class=" hover:text-blue-500 cursor-pointer">
  93. <Delete />
  94. </el-icon>
  95. </div>
  96. </el-form-item>
  97. <el-form-item>
  98. <div>
  99. <el-icon size="24" @click="addCustomeDateItem()" class=" hover:text-blue-500 cursor-pointer">
  100. <Plus />
  101. </el-icon>
  102. </div>
  103. </el-form-item>
  104. </template>
  105. </template>
  106. <el-form-item label="开始时间:" class="w50">
  107. <el-date-picker v-model="form.startDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD"
  108. :disabled="disabledList && disabledList.includes('startDate')" />
  109. </el-form-item>
  110. <el-form-item label="截止时间:" class="w50">
  111. <el-date-picker v-model="form.endDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD"
  112. :disabled="disabledList && disabledList.includes('endDate')" />
  113. </el-form-item>
  114. </el-form>
  115. <GenerateForm ref="generateFormRef" :data="generateFormData" :value="form" />
  116. <div v-if="showLog">
  117. <el-form-item label="操作记录" label-width="7em">
  118. <div class="w-full">
  119. <div v-for="item in form.taskLogs" class=" border-b-2 w-full pl-3">
  120. {{ `${dayjs(item.modTime).format('YYYY-MM-DD HH:mm:ss')} ${item.userName} ${item.content}` }}
  121. </div>
  122. </div>
  123. </el-form-item>
  124. </div>
  125. </div>
  126. </el-dialog>
  127. </template>
  128. <script lang="ts" setup>
  129. import { ref, watch } from 'vue';
  130. import { PRIORITY, TASK_TYPE, TASK_TYPE_FIELD, defalutModalForm, REPEAT_TYPE, CUSTOMER_FORM_URL, defaultGenerateFormData, ALL_CUSTOM, ALL_CLUE, ALL_BUSINESS, ALL_CONTACTS, ALL_ORDERS, ALL_USERS, getTaskType } from "./api";
  131. import { GenerateForm } from "@zmjs/form-design"
  132. import { get, post } from '@/utils/request';
  133. import { Delete, Plus } from "@element-plus/icons-vue"
  134. import { FormInstance, dayjs } from 'element-plus';
  135. import { getFromValue } from '@/utils/tools';
  136. import { Props, Emits } from './type';
  137. const props = defineProps<Props>()
  138. const emits = defineEmits<Emits>();
  139. watch(() => props.saveLoading, (val) => {
  140. if (val == "3") {
  141. formRef.value?.resetFields();
  142. form.value = { ...defalutModalForm };
  143. generateFormRef.value?.reset();
  144. }
  145. })
  146. watch(() => props.visible, (val) => {
  147. if (val) {
  148. get(CUSTOMER_FORM_URL).then(res => {
  149. if (Array.isArray(res.data) && res.data.length > 0) {
  150. generateFormData.value = JSON.parse(res.data[0].config)
  151. }
  152. })
  153. }
  154. })
  155. const customeData = ref<any>([])
  156. const businessData = ref<any>([])
  157. const orderData = ref<any>([])
  158. const clueData = ref<any>([])
  159. watch(() => props.editForm, (val) => {
  160. let taskType = 0;
  161. if (val) {
  162. taskType = getTaskType(val);
  163. }
  164. get(ALL_CUSTOM, {}).then(({ data }) => {
  165. customeData.value = data;//客户
  166. if (taskType == 0) {
  167. taskTypeValueData.value = data;
  168. }
  169. })
  170. get(ALL_BUSINESS, {}).then(({ data }) => {
  171. businessData.value = data;//商机
  172. if (taskType == 1) {
  173. taskTypeValueData.value = data;
  174. }
  175. })
  176. post(ALL_ORDERS, { pageIndex: -1, pageSize: -1 }).then(({ data }) => {
  177. orderData.value = data.record;//销售订单
  178. if (taskType == 2) {
  179. taskTypeValueData.value = data;
  180. }
  181. })
  182. get(ALL_CLUE, {}).then(({ data }) => {
  183. clueData.value = data;//线索
  184. if (taskType == 3) {
  185. taskTypeValueData.value = data;
  186. }
  187. })
  188. get(ALL_CONTACTS, {}).then(({ data }) => {
  189. contactValueData.value = data;//联系人
  190. })
  191. get(ALL_USERS, {}).then(({ data }) => {
  192. executorValueData.value = data;
  193. })
  194. if (val) {
  195. form.value = {
  196. ...val,
  197. taskType,
  198. }
  199. } else {
  200. form.value = { ...defalutModalForm }
  201. }
  202. })
  203. const rules = ref({
  204. taskName: [
  205. { required: true, message: '请输入任务名称', trigger: 'blur' }
  206. ],
  207. priority: [
  208. { required: true, message: '请选择优先级', trigger: 'change' }
  209. ]
  210. })
  211. const form = ref<any>({});
  212. const formRef = ref<FormInstance>();
  213. const generateFormRef = ref<InstanceType<typeof GenerateForm>>();
  214. const generateFormData = ref<any>({ ...defaultGenerateFormData });
  215. function closeVisible() {
  216. formRef.value?.resetFields();
  217. generateFormData.value = { ...defaultGenerateFormData };
  218. generateFormRef.value?.reset()
  219. emits('close')
  220. }
  221. function submitForm(formEl: FormInstance | undefined, isClose: boolean) {
  222. if (!formEl) return
  223. formEl.validate((valid) => {
  224. if (!valid) {
  225. return false
  226. }
  227. const repeatDesignDay = customeDate.value.join(",")
  228. generateFormRef.value?.getData().then((res: any) => {
  229. console.log(`{
  230. ...form.value,
  231. repeatDesignDay,
  232. ...res
  233. }`, {
  234. ...form.value,
  235. repeatDesignDay,
  236. ...res
  237. });
  238. let submitData = getFromValue({
  239. ...form.value,
  240. repeatDesignDay,
  241. ...res
  242. })
  243. emits('submit', submitData, isClose)
  244. }).catch((err: any) => {
  245. console.log(err);
  246. })
  247. })
  248. }
  249. const taskTypeValueData = ref<any>([])
  250. function changeTaskType(value: TASK_VALUE_TYPE) {
  251. form.value = {
  252. ...form.value,
  253. taskType: value,
  254. customId: null, // 客户id 0
  255. businessOpportunityId: null, //商机id 1
  256. orderId: null, // 订单id 2
  257. clueId: null, //线索id 3
  258. contactsId: null, //联系人id
  259. }
  260. switch (value) {
  261. case 0:
  262. taskTypeValueData.value = [];
  263. setTimeout(() => {
  264. taskTypeValueData.value = customeData.value;
  265. }, 500)
  266. break;
  267. case 1:
  268. taskTypeValueData.value = [];
  269. setTimeout(() => {
  270. taskTypeValueData.value = businessData.value;
  271. }, 500)
  272. break;
  273. case 2:
  274. taskTypeValueData.value = [];
  275. setTimeout(() => {
  276. taskTypeValueData.value = orderData.value
  277. }, 500)
  278. break;
  279. case 3:
  280. taskTypeValueData.value = [];
  281. setTimeout(() => {
  282. taskTypeValueData.value = clueData.value;
  283. }, 500)
  284. break;
  285. default:
  286. const _n: never = value;
  287. break;
  288. }
  289. }
  290. const contactValueData = ref<any>([])
  291. const executorValueData = ref<any>([])
  292. function changeRepeat(value: string | number | boolean) {
  293. form.value = {
  294. ...form.value,
  295. isRepeat: value,
  296. repeatType: 0, //重复类型
  297. endType: 1, //结束类型
  298. repeatEndNever: 1,
  299. repeatEndCount: null, //重复指定次数次数后结束
  300. repeatEndDate: null, //重复到指定日期后结束
  301. repeatDesignDay: null, //自定义日期
  302. repeatDesignSameday: null, //自定义周期
  303. }
  304. customeDate.value = [];
  305. }
  306. function changeRepeatType(value: REPEAT_VALUE_TYPE) {
  307. form.value = {
  308. ...form.value,
  309. repeatType: value, //重复类型
  310. endType: 1, //结束类型
  311. repeatEndNever: 1,
  312. repeatEndCount: null, //重复指定次数次数后结束
  313. repeatEndDate: null, //重复到指定日期后结束
  314. repeatDesignDay: null, //自定义日期
  315. repeatDesignSameday: null, //自定义周期
  316. }
  317. customeDate.value = [];
  318. }
  319. function changeEndType(value: string | number | boolean) {
  320. form.value = {
  321. ...form.value,
  322. endType: value, //重复类型
  323. repeatEndNever: value == 1 ? 1 : null,//永不结束
  324. repeatEndCount: null, //重复指定次数次数后结束
  325. repeatEndDate: null, //重复到指定日期后结束
  326. repeatDesignDay: null, //自定义日期
  327. }
  328. }
  329. const customeDate = ref<any>([])
  330. function changeDate(index: number, value: number | undefined) {
  331. customeDate.value[index] = value;
  332. }
  333. function deleteCustomeDateItem(index: number) {
  334. customeDate.value = customeDate.value.filter((_item: number, i: number) => i !== index);
  335. }
  336. function addCustomeDateItem() {
  337. customeDate.value.push(undefined)
  338. }
  339. </script>
  340. <style lang="scss">
  341. .resetSelect {
  342. border: 0;
  343. .el-select__wrapper {
  344. box-shadow: none;
  345. padding-right: 0;
  346. }
  347. .el-select__selected-item {
  348. text-align: right;
  349. }
  350. }
  351. .customeDate {
  352. .el-form-item__content {
  353. justify-content: space-between;
  354. }
  355. }
  356. .el-form-item {
  357. width: 100%;
  358. }
  359. .form {
  360. .w50 {
  361. @apply w-1/2;
  362. }
  363. }
  364. </style>