createTask.vue 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. <template>
  2. <view class="container">
  3. <Step :step="currentStep" :stepsData="currentText" />
  4. <scroll-view class="content" scroll-y>
  5. <!-- 驳回意见提示 -->
  6. <view class="rejection-banner" v-if="rejectionInfo">
  7. <view class="rejection-icon">✕</view>
  8. <view class="rejection-text">驳回意见: {{ rejectionInfo }}</view>
  9. </view>
  10. <!-- 基本信息 -->
  11. <view class="form-section">
  12. <view class="form-item">
  13. <view class="form-label">
  14. <text class="required">*</text>
  15. <text>任务归属</text>
  16. </view>
  17. <!-- <view class="form-input picker-input" :class="{ placeholder: !formData.institution }"
  18. @click="showTaskPopup=true">
  19. {{ formData.institution || '请选择任务归属' }}
  20. <image class="icon" src="/static/image/icon_more.png"></image>
  21. </view> -->
  22. <view class="form-input picker-input" :class="{ placeholder: !formData.deptId }"
  23. @click="showPicker('任务归属',companyData)">
  24. {{ institutionDisplayText || '请选择任务归属' }}
  25. <image class="icon" src="/static/image/icon_more.png"></image>
  26. </view>
  27. </view>
  28. <view class="form-item">
  29. <view class="form-label">
  30. <text class="required">*</text>
  31. <text>归属项目</text>
  32. </view>
  33. <view class="form-input picker-input" :class="{ placeholder: !formData.projectId }"
  34. @click="showPicker('归属项目',companyList)">
  35. {{ belongingProjectDisplayText || '请选择归属项目' }}
  36. <image class="icon" src="/static/image/icon_more.png"></image>
  37. </view>
  38. </view>
  39. <view class="form-item">
  40. <view class="form-label">
  41. <text class="required">*</text>
  42. <text>产品代码</text>
  43. </view>
  44. <view class="form-input picker-input" :class="{ placeholder: !formData.productId }"
  45. @click="showPicker('产品代码',productList)">
  46. {{ productNameDisplayText || '请选择产品代码' }}
  47. <image class="icon" src="/static/image/icon_more.png"></image>
  48. </view>
  49. </view>
  50. <view class="form-item">
  51. <view class="form-label">
  52. <text class="required">*</text>
  53. <text>费用分摊</text>
  54. </view>
  55. <view class="form-input picker-input" :class="{ placeholder: !formData.costShareId }"
  56. @click="showPicker('费用分摊',companyData)">
  57. {{ costAllocationDisplayText || '请选择费用分摊主体' }}
  58. <image class="icon" src="/static/image/icon_more.png"></image>
  59. </view>
  60. </view>
  61. <view class="form-item">
  62. <view class="form-label">
  63. <text class="required">*</text>
  64. <text>添加任务备注</text>
  65. </view>
  66. <EvanSwitch v-model="formData.addRemark"></EvanSwitch>
  67. </view>
  68. <view class="form-item">
  69. <view class="form-label">
  70. <text class="required">*</text>
  71. <text>归属类型</text>
  72. </view>
  73. <view class="form-input picker-input" :class="{ placeholder: !formData.belongType }"
  74. @click="showPicker('归属类型',dictTypeColumns)">
  75. {{ belongTypeDisplayText || '请选择归属类型' }}
  76. <image class="icon" src="/static/image/icon_more.png"></image>
  77. </view>
  78. </view>
  79. <view class="form-item">
  80. <view class="form-label">
  81. <text class="required">*</text>
  82. <text>任务类型</text>
  83. </view>
  84. <view class="form-input picker-input" :class="{ placeholder: !formData.taskType }"
  85. @click="showPicker('任务类型',taskTypeColumns)">
  86. {{ taskTypeDisplayText || '请选择任务类型' }}
  87. <image class="icon" src="/static/image/icon_more.png"></image>
  88. </view>
  89. </view>
  90. <view class="form-item">
  91. <view class="form-label">
  92. <text class="required">*</text>
  93. <text>计划开始时间</text>
  94. </view>
  95. <view class="form-input picker-input" :class="{ placeholder: !formData.planStartTime }"
  96. @click="showStartTimePicker = true">
  97. {{ formData.planStartTime || '请选择计划开始时间' }}
  98. <image class="icon" src="/static/image/icon_more.png"></image>
  99. </view>
  100. </view>
  101. <view class="form-item">
  102. <view class="form-label">
  103. <text class="required">*</text>
  104. <text>计划结束时间</text>
  105. </view>
  106. <view class="form-input picker-input" :class="{ placeholder: !formData.planEndTime }"
  107. @click="showEndTimePicker = true">
  108. {{ formData.planEndTime || '请选择计划结束时间' }}
  109. <image class="icon" src="/static/image/icon_more.png"></image>
  110. </view>
  111. </view>
  112. </view>
  113. </scroll-view>
  114. <view class="next-button" @click="toNext">下一步</view>
  115. <u-picker :title='pickerTitle' :show="showPickerVisible" confirmColor='#576B95' ref="uPicker"
  116. :columns="pickerData" @confirm="confirm" @cancel="cancel">
  117. </u-picker>
  118. <u-datetime-picker :show="showStartTimePicker" v-model="startTimeValue" mode="date"
  119. confirmColor='#576B95' @confirm="onStartTimeConfirm" @cancel="showStartTimePicker = false">
  120. </u-datetime-picker>
  121. <u-datetime-picker :show="showEndTimePicker" v-model="endTimeValue" mode="date"
  122. confirmColor='#576B95' @confirm="onEndTimeConfirm" @cancel="showEndTimePicker = false">
  123. </u-datetime-picker>
  124. <u-popup :show="showBelongingPopup" mode="bottom" round="20" @close="closePopup" closeable>
  125. <view class="popup-content p32">
  126. <view class="popup-header">
  127. <text class="title">归属项目</text>
  128. </view>
  129. <view class="search-box">
  130. <image class="icon" src="/static/image/search.png"></image>
  131. <u-input v-model="searchKeyword" placeholder="请输入归属项目" border="none" clearable />
  132. </view>
  133. <scroll-view scroll-y class="project-list">
  134. <view v-for="(project, index) in filteredProjects" :key="index" class="project-item"
  135. :class="{ active: selectedIndex === index }" @tap="selectProject(project, index)">
  136. <text class="project-name">{{ project.name }}</text>
  137. <image class="icon" src="/static/image/icon_right.png"></image>
  138. </view>
  139. </scroll-view>
  140. </view>
  141. </u-popup>
  142. <u-popup :show="showTaskPopup" mode="bottom" round="16" @close="showTaskPopup = false" safeAreaInsetBottom>
  143. <view class="popup-content">
  144. <view class="popup-header">
  145. <text class="popup-title">任务归属</text>
  146. <image class="close-icon" src="/static/image/icon_cross.png" @click="showTaskPopup=false"></image>
  147. </view>
  148. <view class="two-level-container">
  149. <scroll-view class="primary-list" scroll-y>
  150. <view v-for="(item, index) in primaryOptions" :key="index" class="primary-item"
  151. :class="{ 'primary-active': activePrimaryIndex === index }"
  152. @click="handlePrimarySelect(index)">
  153. <text class="primary-text">{{ item.name }}</text>
  154. </view>
  155. </scroll-view>
  156. <scroll-view class="secondary-list" scroll-y>
  157. <view v-for="(subItem, subIndex) in currentSecondaryOptions" :key="subIndex"
  158. class="secondary-item" :class="{ 'secondary-active': selectedSecondaryItem === subItem }"
  159. @click="handleSecondarySelect(subItem)">
  160. <text class="secondary-text">{{ subItem }}</text>
  161. <u-icon v-if="selectedSecondaryItem === subItem" name="checkbox-mark" color="#2979ff"
  162. size="20" />
  163. </view>
  164. </scroll-view>
  165. </view>
  166. <view class="popup-footer">
  167. <button class="confirm-btn" @click="handleConfirm">确定</button>
  168. </view>
  169. </view>
  170. </u-popup>
  171. </view>
  172. </template>
  173. <script>
  174. import {
  175. company,
  176. getAllData,//获取项目所有数据
  177. queryAllProduct,//获取公司所有产品
  178. queryAllData//获取任务类型
  179. } from '@/api/task.js';
  180. import utils from '@/utils/common.js'
  181. import Step from '@/pages_task/components/step.vue'
  182. import EvanSwitch from '@/components/evan-switch.vue'
  183. export default {
  184. components: {
  185. Step,
  186. EvanSwitch
  187. },
  188. data() {
  189. return {
  190. taskTypeDict:[],//任务类型字典
  191. taskType:[],//任务类型
  192. taskTypeOriginalData:[],//任务类型原始数据(包含dictLabel和dictValue)
  193. companyList:[],//归属项目
  194. projectData:[],//项目数据(持久化存储)
  195. productList:[],//产品列表
  196. companyData:[],
  197. userInfo:{},
  198. showTaskPopup: false,
  199. primaryOptions: [{
  200. id: 1,
  201. name: '中药事业部',
  202. children: ['中药一部', '中药二部', '中药三部', '中药四部']
  203. },
  204. {
  205. id: 2,
  206. name: '事业1组',
  207. children: ['事业1组-项目部', '事业1组-市场部', '事业1组-技术部']
  208. },
  209. ],
  210. activePrimaryIndex: 0,
  211. currentSecondaryOptions: [],
  212. selectedSecondaryItem: '',
  213. selectedPrimaryItem: null,
  214. selectedIndex: -1,
  215. selectedProject: null,
  216. belongingprojects: [{
  217. name: '学术交流项目'
  218. },
  219. {
  220. name: '科学调研项目'
  221. },
  222. {
  223. name: '2026年1月医学研究项目'
  224. },
  225. {
  226. name: '2026年2月医学研究项目'
  227. },
  228. {
  229. name: '2026年3月医学研究项目'
  230. }
  231. ],
  232. searchKeyword: '',
  233. showBelongingPopup: false,
  234. showPickerVisible: false,
  235. costColumns: [
  236. ['主体1', '主体2', '主体3'],
  237. ],
  238. taskTypeColumns: [
  239. // ['类型1', '类型2', '类型3'],
  240. ],
  241. currentStep: 1,
  242. currentText: [{
  243. id: 1,
  244. stepNumber: 1,
  245. title: '填写任务'
  246. },
  247. {
  248. id: 2,
  249. stepNumber: 2,
  250. title: '选择客户'
  251. },
  252. {
  253. id: 3,
  254. stepNumber: 3,
  255. title: '积分设置'
  256. }
  257. ],
  258. rejectionInfo: '',
  259. formData: {
  260. costShareId: '',
  261. planStartTime: '',
  262. planEndTime: '',
  263. belongType: '',
  264. deptId: '',
  265. projectId: '',
  266. productId: '',
  267. taskType: '',
  268. addRemark: false
  269. },
  270. originalCompanyData: null,
  271. pickerTitle: '默认标题',
  272. pickerData: [],
  273. companyId:'',
  274. showStartTimePicker: false,
  275. showEndTimePicker: false,
  276. startTimeValue: new Date(),
  277. endTimeValue: new Date(),
  278. }
  279. },
  280. onLoad: async function(options) {
  281. try {
  282. this.taskTypeDict = await utils.getDicts("task_type");//任务类型
  283. this.belongTypeList = await utils.getDicts("task_belong_type");//任务类型
  284. } catch (e) {
  285. console.log('获取字典数据失败:', e)
  286. }
  287. this.userInfo=JSON.parse(uni.getStorageSync("userInfo"))||''
  288. if (options.rejectionInfo) {
  289. this.rejectionInfo = decodeURIComponent(options.rejectionInfo)
  290. }
  291. // 获取用户信息
  292. const userInfoStr = uni.getStorageSync('userInfo')
  293. this.userInfo = userInfoStr ? JSON.parse(userInfoStr) : {}
  294. console.log(this.userInfo);
  295. // 加载信息
  296. this.companyId = this.userInfo.companyId || 1
  297. // 设置默认日期为当天
  298. this.formData.planStartTime = this.formatDateTime(new Date());
  299. this.formData.planEndTime = this.formatDateTime(new Date());
  300. },
  301. computed: {
  302. taskTypeDisplayText() {
  303. console.log('计算taskTypeDisplayText, formData.taskType:', this.formData.taskType);
  304. console.log('计算taskTypeDisplayText, taskTypeOriginalData:', this.taskTypeOriginalData);
  305. if (!this.formData.taskType || !this.taskTypeOriginalData) {
  306. return '';
  307. }
  308. const selectedType = this.taskTypeOriginalData.find(item => item.dictValue === this.formData.taskType);
  309. console.log('找到的selectedType:', selectedType);
  310. return selectedType ? selectedType.dictLabel : '';
  311. },
  312. institutionDisplayText() {
  313. if (!this.formData.deptId || !this.originalCompanyData) {
  314. return '';
  315. }
  316. const selectedItem = this.originalCompanyData.find(item => item.deptId === this.formData.deptId);
  317. return selectedItem ? selectedItem.deptName : '';
  318. },
  319. costAllocationDisplayText() {
  320. if (!this.formData.costShareId || !this.originalCompanyData) {
  321. return '';
  322. }
  323. const selectedItem = this.originalCompanyData.find(item => item.deptId === this.formData.costShareId);
  324. return selectedItem ? selectedItem.deptName : '';
  325. },
  326. belongingProjectDisplayText() {
  327. console.log('计算belongingProjectDisplayText:', this.formData.projectId, this.projectData);
  328. if (!this.formData.projectId || !this.projectData) {
  329. console.log('formData.projectId或projectData为空');
  330. return '';
  331. }
  332. const selectedItem = this.projectData.find(item => item.id === this.formData.projectId);
  333. console.log('找到的项目:', selectedItem);
  334. return selectedItem ? selectedItem.projectName : '';
  335. },
  336. productNameDisplayText() {
  337. if (!this.formData.productId || !this.productList) {
  338. return '';
  339. }
  340. const selectedItem = this.productList.find(item => item.id === this.formData.productId);
  341. return selectedItem ? selectedItem.productName : '';
  342. },
  343. belongTypeDisplayText() {
  344. if (!this.formData.belongType || !this.belongTypeList) {
  345. return '';
  346. }
  347. const selectedItem = this.belongTypeList.find(item => item.dictValue === this.formData.belongType);
  348. return selectedItem ? selectedItem.dictLabel : '';
  349. }
  350. },
  351. methods: {
  352. //任务类型
  353. queryAllData(){
  354. return new Promise((resolve, reject) => {
  355. if(!this.formData.productId){
  356. uni.showToast({
  357. title: '请先选择产品',
  358. icon: 'none'
  359. })
  360. resolve();
  361. return
  362. }
  363. let data={
  364. companyId:this.userInfo.companyId||'',
  365. deptId:this.formData.deptId||'',
  366. productId:this.formData.productId||'',
  367. }
  368. queryAllData(data).then(res => {
  369. if (res.code === 200) {
  370. // 处理任务类型
  371. this.taskType = res.data || []
  372. console.log('company接口返回数据:', res)
  373. // 处理taskTypeIds,获取对应的字典数据
  374. if (res.data && res.data.length > 0) {
  375. const firstData = res.data[0];
  376. if (firstData.taskTypeIds) {
  377. // 分割taskTypeIds为数组
  378. const taskTypeIdsArray = firstData.taskTypeIds.split(',');
  379. // 从字典表中筛选出对应的项
  380. const filteredTaskTypes = this.taskTypeDict.filter(item =>
  381. taskTypeIdsArray.includes(item.dictValue)
  382. );
  383. // 保存原始数据(包含dictLabel和dictValue)
  384. this.taskTypeOriginalData = filteredTaskTypes;
  385. // 提取dictLabel并放到taskTypeColumns中
  386. const taskTypeLabels = filteredTaskTypes.map(item => item.dictLabel);
  387. this.taskTypeColumns = [taskTypeLabels];
  388. console.log('处理后的taskTypeColumns:', this.taskTypeColumns);
  389. console.log('任务类型原始数据:', this.taskTypeOriginalData);
  390. }
  391. }
  392. }
  393. resolve(res);
  394. }).catch(err => {
  395. console.error('获取任务类型失败:', err);
  396. reject(err);
  397. });
  398. });
  399. },
  400. //获取公司所有产品
  401. async queryAllProduct(){
  402. return new Promise((resolve, reject) => {
  403. let data={
  404. companyId:this.userInfo.companyId||'',
  405. }
  406. queryAllProduct(data).then(res => {
  407. if (res.code === 200) {
  408. // 处理公司所有产品数据
  409. this.productList = res.data || []
  410. console.log('company接口返回数据:', res)
  411. }
  412. resolve(res);
  413. }).catch(err => {
  414. console.error('获取公司所有产品失败:', err);
  415. reject(err);
  416. });
  417. });
  418. },
  419. // 归属项目
  420. async getAllData(){
  421. return new Promise((resolve, reject) => {
  422. let data={
  423. companyId:this.userInfo.companyId||'',
  424. deptId:this.userInfo.deptId||'',
  425. productCode:this.userInfo.productCode||''
  426. }
  427. getAllData(data).then(res => {
  428. if (res.code === 200) {
  429. // 处理公司项目设置列表数据
  430. this.companyList = res.data || []
  431. // 保存项目数据用于显示
  432. this.projectData = res.data || []
  433. console.log('company接口返回数据:', res)
  434. console.log('companyList数据结构:', this.companyList)
  435. }
  436. resolve(res);
  437. }).catch(err => {
  438. console.error('获取公司项目设置失败:', err);
  439. reject(err);
  440. });
  441. });
  442. },
  443. async company() {
  444. return new Promise((resolve, reject) => {
  445. try {
  446. uni.showLoading({
  447. title: '加载中...'
  448. })
  449. // 调用company接口获取公司项目设置列表
  450. company(this.companyId).then(companyRes => {
  451. uni.hideLoading()
  452. if (companyRes.code === 200) {
  453. // 处理公司项目设置列表数据
  454. this.companyData = companyRes.data || []
  455. console.log('company接口返回数据:', companyRes)
  456. // 这里可以根据接口返回的数据进行页面初始化,比如填充项目列表
  457. }
  458. resolve(companyRes);
  459. }).catch(e => {
  460. uni.hideLoading()
  461. console.error('加载信息失败', e)
  462. uni.showToast({
  463. title: '网络错误',
  464. icon: 'none'
  465. })
  466. reject(e);
  467. });
  468. } catch (e) {
  469. uni.hideLoading()
  470. console.error('加载信息失败', e)
  471. uni.showToast({
  472. title: '网络错误',
  473. icon: 'none'
  474. })
  475. reject(e);
  476. }
  477. });
  478. },
  479. submitInfo() {
  480. info(this.userInfo.companyId).then(res => {
  481. if (res.code === 200) {
  482. console.log('公司项目设置:', res.data);
  483. // 处理公司项目设置数据
  484. }
  485. }).catch(err => {
  486. console.error('获取公司项目设置失败:', err);
  487. });
  488. },
  489. handlePrimarySelect(index) {
  490. this.activePrimaryIndex = index;
  491. this.currentSecondaryOptions = this.primaryOptions[index].children || [];
  492. this.selectedSecondaryItem = '';
  493. },
  494. handleSecondarySelect(item) {
  495. this.selectedSecondaryItem = item;
  496. this.selectedPrimaryItem = this.primaryOptions[this.activePrimaryIndex];
  497. },
  498. handleConfirm() {
  499. if (this.selectedSecondaryItem) {
  500. const displayText = `${this.selectedPrimaryItem.name} > ${this.selectedSecondaryItem}`;
  501. this.formData.belongType = displayText;
  502. this.showTaskPopup = false;
  503. } else {
  504. uni.showToast({
  505. title: '请选择二级部门',
  506. icon: 'none'
  507. });
  508. }
  509. },
  510. closePopup() {
  511. this.showBelongingPopup = false;
  512. this.searchKeyword = '';
  513. this.selectedIndex = -1;
  514. },
  515. selectProject(project, index) {
  516. this.selectedIndex = index;
  517. this.selectedProject = project;
  518. this.formData.belongingProject = project.name;
  519. setTimeout(() => {
  520. this.showBelongingPopup = false;
  521. this.searchKeyword = '';
  522. this.selectedIndex = -1;
  523. }, 300);
  524. },
  525. async showPicker(title, data) {
  526. // 根据不同的title调用对应的请求方法
  527. if (title === '任务归属' || title === '费用分摊') {
  528. // 调用company()获取任务归属和费用分摊数据
  529. await this.company();
  530. data = this.companyData;
  531. } else if (title === '归属项目') {
  532. // 调用getAllData()获取归属项目数据
  533. await this.getAllData();
  534. data = this.companyList;
  535. console.log('归属项目数据:', data);
  536. } else if (title === '产品代码') {
  537. // 调用queryAllProduct()获取产品代码数据
  538. await this.queryAllProduct();
  539. data = this.productList;
  540. } else if (title === '任务类型') {
  541. // queryAllData()获取任务类型数据
  542. await this.queryAllData();
  543. // 使用处理后的taskTypeColumns作为数据
  544. data = this.taskTypeColumns;
  545. console.log('任务类型数据:', data);
  546. } else if (title === '归属类型') {
  547. // 归属类型数据已经在onLoad中获取
  548. data = this.belongTypeList;
  549. console.log('归属类型数据:', data);
  550. }
  551. // 处理任务归属和费用分摊数据,将deptStr作为显示文本
  552. if ((title === '任务归属' || title === '费用分摊') && data && data.length > 0) {
  553. // 转换为picker需要的格式
  554. this.pickerData = [data.map(item => item.deptStr)]
  555. // 保存原始数据,用于后续获取deptId
  556. this.originalCompanyData = data
  557. } else if (title === '归属项目' && data && data.length > 0) {
  558. // 处理归属项目数据,将projectName作为显示文本
  559. this.pickerData = [data.map(item => item.projectName)]
  560. // 保存原始数据,用于后续获取productId
  561. this.originalCompanyData = data
  562. } else if (title === '产品代码' && data && data.length > 0) {
  563. // 处理产品代码数据,将productName作为显示文本
  564. this.pickerData = [data.map(item => item.productName)]
  565. // 保存原始数据,用于后续获取productCode
  566. this.originalCompanyData = data
  567. } else if (title === '归属类型' && data && data.length > 0) {
  568. // 处理归属类型数据,将dictLabel作为显示文本
  569. this.pickerData = [data.map(item => item.dictLabel)]
  570. // 保存原始数据,用于后续获取dictType
  571. this.originalCompanyData = data
  572. } else {
  573. this.pickerData = data
  574. this.originalCompanyData = null
  575. }
  576. this.pickerTitle = title
  577. console.log('打开picker, pickerTitle:', this.pickerTitle);
  578. console.log('pickerData:', this.pickerData);
  579. this.showPickerVisible = true
  580. },
  581. confirm(e) {
  582. console.log('confirm事件返回值:', e);
  583. console.log('pickerTitle:', this.pickerTitle);
  584. console.log('e.value:', e.value);
  585. if (e.value && e.value.length > 0) {
  586. if (this.pickerTitle === '费用分摊') {
  587. // e.value[0]是选中的文本值(deptStr)
  588. const selectedDeptStr = e.value[0];
  589. console.log('选中的费用分摊文本:', selectedDeptStr);
  590. console.log('originalCompanyData:', this.originalCompanyData);
  591. // 从originalCompanyData中找到对应的项
  592. const selectedItem = this.originalCompanyData.find(item => item.deptStr === selectedDeptStr);
  593. if (selectedItem) {
  594. // 保存deptId到表单(存储id值)
  595. this.formData.costShareId = selectedItem.deptId;
  596. console.log('设置formData.costShareId为:', selectedItem.deptId);
  597. } else {
  598. this.formData.costShareId = '';
  599. console.log('未找到对应的费用分摊');
  600. }
  601. } else if (this.pickerTitle === '任务类型') {
  602. // e.value[0]是选中的文本值(dictLabel)
  603. const selectedLabel = e.value[0];
  604. console.log('选中的任务类型文本:', selectedLabel);
  605. console.log('taskTypeOriginalData:', this.taskTypeOriginalData);
  606. // 从taskTypeOriginalData中找到对应的项
  607. const selectedType = this.taskTypeOriginalData.find(item => item.dictLabel === selectedLabel);
  608. if (selectedType) {
  609. this.formData.taskType = selectedType.dictValue;
  610. console.log('设置formData.taskType为:', selectedType.dictValue);
  611. } else {
  612. }
  613. } else if (this.pickerTitle === '任务归属' && this.originalCompanyData) {
  614. // e.value[0]是选中的文本值(deptStr)
  615. const selectedDeptStr = e.value[0];
  616. console.log('选中的任务归属文本:', selectedDeptStr);
  617. console.log('originalCompanyData:', this.originalCompanyData);
  618. // 从originalCompanyData中找到对应的项
  619. const selectedItem = this.originalCompanyData.find(item => item.deptStr === selectedDeptStr);
  620. if (selectedItem) {
  621. // 保存deptId到表单(存储id值)
  622. this.formData.deptId = selectedItem.deptId;
  623. console.log('设置formData.deptId为:', selectedItem.deptId);
  624. } else {
  625. }
  626. } else if (this.pickerTitle === '归属项目' && this.originalCompanyData) {
  627. // e.value[0]是选中的文本值(projectName)
  628. const selectedProjectName = e.value[0];
  629. console.log('选中的归属项目文本:', selectedProjectName);
  630. console.log('originalCompanyData:', this.originalCompanyData);
  631. // 从originalCompanyData中找到对应的项
  632. const selectedItem = this.originalCompanyData.find(item => item.projectName === selectedProjectName);
  633. if (selectedItem) {
  634. // 保存id到表单(存储id值)
  635. this.formData.projectId = selectedItem.id;
  636. // 保存productId到表单
  637. this.formData.productId = selectedItem.productId;
  638. console.log('设置formData.projectId为:', selectedItem.id);
  639. } else {
  640. }
  641. } else if (this.pickerTitle === '产品代码' && this.originalCompanyData) {
  642. // e.value[0]是选中的文本值(productName)
  643. const selectedProductName = e.value[0];
  644. console.log('选中的产品代码文本:', selectedProductName);
  645. console.log('originalCompanyData:', this.originalCompanyData);
  646. // 从originalCompanyData中找到对应的项
  647. const selectedItem = this.originalCompanyData.find(item => item.productName === selectedProductName);
  648. if (selectedItem) {
  649. // 保存id到表单
  650. this.formData.productId = selectedItem.id;
  651. // 保存id用于获取任务类型
  652. console.log('设置formData.productId为:', selectedItem.id);
  653. } else {
  654. }
  655. } else if (this.pickerTitle === '归属类型' && this.originalCompanyData) {
  656. // e.value[0]是选中的文本值(dictLabel)
  657. const selectedLabel = e.value[0];
  658. console.log('选中的归属类型文本:', selectedLabel);
  659. console.log('originalCompanyData:', this.originalCompanyData);
  660. // 从originalCompanyData中找到对应的项
  661. const selectedItem = this.originalCompanyData.find(item => item.dictLabel === selectedLabel);
  662. if (selectedItem) {
  663. // 保存dictValue到表单的belongType字段
  664. this.formData.belongType = selectedItem.dictValue;
  665. console.log('设置formData.belongType为:', selectedItem.dictValue);
  666. } else {
  667. console.log('未找到对应的归属类型');
  668. }
  669. }
  670. }
  671. this.showPickerVisible = false
  672. },
  673. cancel() {
  674. this.showPickerVisible = false
  675. },
  676. toNext() {
  677. // 保存任务表单数据到本地存储
  678. uni.setStorageSync('taskFormData', JSON.stringify(this.formData))
  679. uni.navigateTo({
  680. url: '/pages_task/selectCustomer'
  681. })
  682. },
  683. onStartTimeConfirm(e) {
  684. this.formData.planStartTime = this.formatDateTime(e.value);
  685. this.showStartTimePicker = false;
  686. },
  687. onEndTimeConfirm(e) {
  688. this.formData.planEndTime = this.formatDateTime(e.value);
  689. this.showEndTimePicker = false;
  690. },
  691. formatDateTime(timestamp) {
  692. const date = new Date(timestamp);
  693. const year = date.getFullYear();
  694. const month = String(date.getMonth() + 1).padStart(2, '0');
  695. const day = String(date.getDate()).padStart(2, '0');
  696. // const hours = String(date.getHours()).padStart(2, '0');
  697. // const minutes = String(date.getMinutes()).padStart(2, '0');
  698. // const seconds = String(date.getSeconds()).padStart(2, '0');
  699. // ${hours}:${minutes}:${seconds}
  700. return `${year}-${month}-${day}`;
  701. }
  702. }
  703. }
  704. </script>
  705. <style lang="scss" scoped>
  706. .container {
  707. min-height: 100vh;
  708. background: #F7F8FA;
  709. display: flex;
  710. flex-direction: column;
  711. position: relative;
  712. &::before {
  713. content: '';
  714. position: absolute;
  715. top: 0;
  716. left: 0;
  717. right: 0;
  718. width: 100%;
  719. height: 544rpx;
  720. background: linear-gradient(180deg, #E4EFFE 0%, rgba(228, 239, 254, 0) 100%);
  721. }
  722. .content {
  723. flex: 1;
  724. box-sizing: border-box;
  725. .rejection-banner {
  726. display: flex;
  727. align-items: center;
  728. padding: 24rpx;
  729. background: #FF5030;
  730. color: #fff;
  731. margin: 24rpx;
  732. border-radius: 8rpx;
  733. .rejection-icon {
  734. width: 40rpx;
  735. height: 40rpx;
  736. border-radius: 50%;
  737. background: rgba(255, 255, 255, 0.3);
  738. display: flex;
  739. align-items: center;
  740. justify-content: center;
  741. font-size: 24rpx;
  742. margin-right: 16rpx;
  743. }
  744. .rejection-text {
  745. flex: 1;
  746. font-size: 28rpx;
  747. line-height: 1.5;
  748. }
  749. }
  750. .form-section {
  751. background: #fff;
  752. margin: 20rpx;
  753. border-radius: 16rpx;
  754. padding: 32rpx;
  755. .form-item {
  756. display: flex;
  757. justify-content: space-between;
  758. align-items: center;
  759. border-bottom: 1px solid #EBEDF0;
  760. padding: 30rpx 0;
  761. &:last-child {
  762. border-bottom: 0;
  763. }
  764. .form-label {
  765. display: flex;
  766. align-items: center;
  767. font-size: 28rpx;
  768. color: #333;
  769. margin-bottom: 16rpx;
  770. .required {
  771. color: #CF3546;
  772. margin-right: 4rpx;
  773. }
  774. }
  775. .txt {
  776. font-size: 28rpx;
  777. color: #333333;
  778. }
  779. .form-input {
  780. flex: 1;
  781. font-size: 28rpx;
  782. color: #C8C9CC;
  783. &.placeholder {
  784. color: #C8C9CC;
  785. }
  786. &.picker-input {
  787. display: flex;
  788. align-items: center;
  789. justify-content: flex-end;
  790. }
  791. .icon {
  792. width: 36rpx;
  793. height: 36rpx;
  794. }
  795. }
  796. }
  797. }
  798. }
  799. .next-button {
  800. text-align: center;
  801. font-size: 32rpx;
  802. color: #FFFFFF;
  803. height: 88rpx;
  804. line-height: 88rpx;
  805. background: #388BFF;
  806. border-radius: 200rpx;
  807. margin: 32rpx;
  808. }
  809. }
  810. ::v-deep .u-popup__content {
  811. border-radius: 40rpx 40rpx 0 0 !important;
  812. }
  813. .popup-content {
  814. border-radius: 40rpx 40rpx 0rpx 0rpx;
  815. height: 70vh;
  816. background-color: #fff;
  817. .popup-header {
  818. padding: 40rpx 30rpx 20rpx;
  819. text-align: center;
  820. .close-icon {
  821. width: 44rpx;
  822. height: 44rpx;
  823. position: absolute;
  824. right: 32rpx;
  825. }
  826. flex-shrink: 0;
  827. .title {
  828. font-size: 32rpx;
  829. font-weight: 600;
  830. color: #333;
  831. }
  832. .popup-title {
  833. font-size: 32rpx;
  834. font-weight: 600;
  835. color: #333;
  836. }
  837. }
  838. .search-box {
  839. display: flex;
  840. align-items: center;
  841. background: #F7F8FA;
  842. border-radius: 38rpx;
  843. padding: 16rpx 28rpx;
  844. margin-bottom: 24rpx;
  845. .icon {
  846. width: 26rpx;
  847. height: 26rpx;
  848. margin-right: 10rpx;
  849. }
  850. }
  851. .project-list {
  852. height: calc(100% - 200rpx);
  853. .project-item {
  854. display: flex;
  855. justify-content: space-between;
  856. align-items: center;
  857. padding: 28rpx 0;
  858. font-size: 28rpx;
  859. border-bottom: 1rpx solid #eee;
  860. &:active {
  861. background-color: #f9f9f9;
  862. }
  863. &.active {
  864. .project-name {
  865. font-weight: 500;
  866. color: #388BFF;
  867. }
  868. .icon {
  869. opacity: 1;
  870. }
  871. }
  872. .project-name {
  873. color: #333;
  874. transition: all 0.2s ease;
  875. }
  876. .icon {
  877. width: 36rpx;
  878. height: 36rpx;
  879. opacity: 0;
  880. transition: opacity 0.2s ease;
  881. }
  882. }
  883. }
  884. .two-level-container {
  885. display: flex;
  886. flex: 1;
  887. border-top: 1rpx solid #f5f5f5;
  888. .primary-list {
  889. width: 40%;
  890. background-color: #f8f9fa;
  891. .primary-item {
  892. padding: 28rpx 20rpx;
  893. background: #F2F3F5;
  894. &:active {
  895. background: #FFFFFF;
  896. }
  897. &.primary-active {
  898. position: relative;
  899. background-color: #fff;
  900. &::before {
  901. content: '';
  902. position: absolute;
  903. top: 50%;
  904. left: 0;
  905. transform: translateY(-50%);
  906. width: 8rpx;
  907. height: 32rpx;
  908. background: #388BFF;
  909. }
  910. .primary-text {
  911. font-weight: 500;
  912. }
  913. }
  914. .primary-text {
  915. font-size: 28rpx;
  916. color: #666;
  917. }
  918. }
  919. }
  920. .secondary-list {
  921. width: 60%;
  922. padding: 0 20rpx;
  923. .secondary-item {
  924. display: flex;
  925. justify-content: space-between;
  926. align-items: center;
  927. padding: 28rpx 10rpx;
  928. font-size: 28rpx;
  929. color: #333;
  930. &.secondary-active {
  931. font-weight: 500;
  932. color: #388BFF;
  933. }
  934. }
  935. }
  936. }
  937. .popup-footer {
  938. padding: 20rpx 30rpx 40rpx;
  939. background-color: #fff;
  940. border-top: 1rpx solid #f5f5f5;
  941. flex-shrink: 0;
  942. .confirm-btn {
  943. width: 100%;
  944. height: 88rpx;
  945. line-height: 88rpx;
  946. background-color: #2979ff;
  947. color: #fff;
  948. font-size: 32rpx;
  949. border-radius: 200rpx 200rpx 200rpx 200rpx;
  950. &:active {
  951. opacity: 0.8;
  952. }
  953. }
  954. }
  955. }
  956. @media (prefers-color-scheme: dark) {
  957. .popup-content {
  958. background-color: #1e1e1e;
  959. .popup-header {
  960. .title,
  961. .popup-title {
  962. color: #fff;
  963. }
  964. }
  965. .two-level-container {
  966. .primary-list {
  967. background-color: #2d2d2d;
  968. border-right-color: #3d3d3d;
  969. .primary-item {
  970. border-bottom-color: #3d3d3d;
  971. &:active {
  972. background-color: #3d3d3d;
  973. }
  974. &.primary-active {
  975. background-color: #3d3d3d;
  976. .primary-text {
  977. color: #2979ff;
  978. }
  979. }
  980. .primary-text {
  981. color: #ccc;
  982. }
  983. }
  984. }
  985. .secondary-list {
  986. .secondary-item {
  987. border-bottom-color: #3d3d3d;
  988. &:active {
  989. background-color: #3d3d3d;
  990. }
  991. &.secondary-active {
  992. background-color: #2d2d2d;
  993. }
  994. .secondary-text {
  995. color: #fff;
  996. }
  997. }
  998. }
  999. }
  1000. .popup-footer {
  1001. background-color: #1e1e1e;
  1002. border-top-color: #3d3d3d;
  1003. }
  1004. }
  1005. }
  1006. </style>