revision-task-modal.component.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, ViewEncapsulation } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { FormsModule } from '@angular/forms';
  4. import { RevisionType, RevisionTask, RevisionTaskService } from '../../../../app/pages/services/revision-task.service';
  5. interface SpaceOption {
  6. id: string;
  7. name: string;
  8. selected: boolean;
  9. }
  10. @Component({
  11. selector: 'app-revision-task-modal',
  12. standalone: true,
  13. imports: [CommonModule, FormsModule],
  14. templateUrl: './revision-task-modal.component.html',
  15. styleUrls: ['./revision-task-modal.component.scss'],
  16. styles: [`
  17. /* 🔥 响应式设计:网页端保持原始大小,企业微信端使用紧凑布局 */
  18. /* 💻 窄屏适配(<= 600px)- 企业微信侧边栏 */
  19. @media (max-width: 600px) {
  20. /* 模态框容器 */
  21. app-revision-task-modal .modal-container {
  22. width: 95vw !important;
  23. max-width: 95vw !important;
  24. max-height: 85vh !important;
  25. overflow-y: auto !important;
  26. }
  27. /* 标题 */
  28. app-revision-task-modal .modal-header h3 {
  29. font-size: 14px !important;
  30. }
  31. /* 表单区块 */
  32. app-revision-task-modal .form-section {
  33. margin-bottom: 16px !important;
  34. }
  35. /* 标签 */
  36. app-revision-task-modal .section-label {
  37. font-size: 11px !important;
  38. font-weight: 700 !important;
  39. margin-bottom: 6px !important;
  40. }
  41. /* 任务类型 */
  42. app-revision-task-modal .task-type-options {
  43. gap: 8px !important;
  44. }
  45. app-revision-task-modal .task-type-option {
  46. padding: 10px !important;
  47. }
  48. app-revision-task-modal .task-type-option h4 {
  49. font-size: 13px !important;
  50. margin-bottom: 2px !important;
  51. }
  52. app-revision-task-modal .task-type-option p {
  53. font-size: 10px !important;
  54. }
  55. /* 🔥 空间选择器 - 单列 */
  56. app-revision-task-modal .space-selector {
  57. display: grid !important;
  58. grid-template-columns: 1fr !important;
  59. gap: 6px !important;
  60. padding: 8px !important;
  61. max-height: 180px !important;
  62. overflow-y: auto !important;
  63. }
  64. app-revision-task-modal .space-item {
  65. display: flex !important;
  66. align-items: center !important;
  67. gap: 8px !important;
  68. padding: 8px 10px !important;
  69. min-height: 36px !important;
  70. }
  71. app-revision-task-modal .space-item input[type="checkbox"] {
  72. flex-shrink: 0 !important;
  73. width: 14px !important;
  74. height: 14px !important;
  75. }
  76. app-revision-task-modal .space-item span {
  77. flex: 1 !important;
  78. font-size: 12px !important;
  79. font-weight: 600 !important;
  80. white-space: normal !important;
  81. overflow: visible !important;
  82. word-wrap: break-word !important;
  83. }
  84. app-revision-task-modal .toggle-all-btn {
  85. font-size: 11px !important;
  86. padding: 4px 10px !important;
  87. }
  88. app-revision-task-modal .selected-count {
  89. font-size: 10px !important;
  90. }
  91. /* 🔥 时间选择器 - 单列 */
  92. app-revision-task-modal .time-selector {
  93. display: grid !important;
  94. grid-template-columns: 1fr !important;
  95. gap: 6px !important;
  96. }
  97. app-revision-task-modal .time-option {
  98. padding: 10px 12px !important;
  99. min-height: 36px !important;
  100. font-size: 12px !important;
  101. }
  102. app-revision-task-modal .time-option input[type="radio"] {
  103. width: 14px !important;
  104. height: 14px !important;
  105. }
  106. /* 描述框 */
  107. app-revision-task-modal textarea {
  108. min-height: 80px !important;
  109. font-size: 12px !important;
  110. padding: 8px !important;
  111. }
  112. /* 其他 */
  113. app-revision-task-modal .char-count {
  114. font-size: 10px !important;
  115. }
  116. app-revision-task-modal .info-box {
  117. padding: 8px !important;
  118. font-size: 10px !important;
  119. }
  120. app-revision-task-modal .modal-actions button {
  121. padding: 10px 20px !important;
  122. font-size: 13px !important;
  123. }
  124. }
  125. `],
  126. changeDetection: ChangeDetectionStrategy.OnPush,
  127. encapsulation: ViewEncapsulation.None
  128. })
  129. export class RevisionTaskModalComponent {
  130. @Input() visible: boolean = false;
  131. @Input() projectId: string = '';
  132. @Input() availableSpaces: SpaceOption[] = [];
  133. @Input() currentUser: any = null;
  134. @Output() close = new EventEmitter<void>();
  135. @Output() created = new EventEmitter<string>();
  136. // 表单数据
  137. taskType: RevisionType = 'major';
  138. selectedSpaces: SpaceOption[] = [];
  139. estimatedDays: string = '2-3天';
  140. customDays: number = 3;
  141. description: string = '';
  142. // 预设时间选项
  143. timeOptions = [
  144. { value: '2-3天', label: '2-3天' },
  145. { value: '3-5天', label: '3-5天' },
  146. { value: '5-7天', label: '5-7天' },
  147. { value: 'custom', label: '自定义' }
  148. ];
  149. submitting: boolean = false;
  150. constructor(
  151. private revisionTaskService: RevisionTaskService,
  152. private cdr: ChangeDetectorRef
  153. ) {}
  154. ngOnChanges(): void {
  155. if (this.visible) {
  156. // 🔍 调试:输出空间数据
  157. console.log('📋 [改图任务] 可用空间列表:', this.availableSpaces);
  158. console.log('📋 [改图任务] 空间数量:', this.availableSpaces.length);
  159. if (this.availableSpaces.length > 0) {
  160. console.log('📋 [改图任务] 第一个空间:', this.availableSpaces[0]);
  161. }
  162. // 重置表单
  163. this.resetForm();
  164. }
  165. }
  166. /**
  167. * 切换空间选择
  168. */
  169. toggleSpace(space: SpaceOption): void {
  170. space.selected = !space.selected;
  171. this.updateSelectedSpaces();
  172. this.cdr.markForCheck();
  173. }
  174. /**
  175. * 全选/取消全选
  176. */
  177. toggleAllSpaces(): void {
  178. const allSelected = this.selectedSpaces.length === this.availableSpaces.length;
  179. this.availableSpaces.forEach(space => {
  180. space.selected = !allSelected;
  181. });
  182. this.updateSelectedSpaces();
  183. this.cdr.markForCheck();
  184. }
  185. /**
  186. * 更新已选空间列表
  187. */
  188. private updateSelectedSpaces(): void {
  189. this.selectedSpaces = this.availableSpaces.filter(s => s.selected);
  190. }
  191. /**
  192. * 切换工单类型
  193. */
  194. onTypeChange(): void {
  195. // 小修改默认不需要选择空间和时间
  196. if (this.taskType === 'minor') {
  197. this.availableSpaces.forEach(s => s.selected = false);
  198. this.updateSelectedSpaces();
  199. }
  200. this.cdr.markForCheck();
  201. }
  202. /**
  203. * 检查表单是否有效
  204. */
  205. isFormValid(): boolean {
  206. if (!this.description.trim()) return false;
  207. if (this.taskType === 'major') {
  208. if (this.selectedSpaces.length === 0) return false;
  209. if (this.estimatedDays === 'custom' && (!this.customDays || this.customDays < 1)) {
  210. return false;
  211. }
  212. }
  213. return true;
  214. }
  215. /**
  216. * 提交创建工单
  217. */
  218. async submit(): Promise<void> {
  219. if (!this.isFormValid() || this.submitting) return;
  220. this.submitting = true;
  221. this.cdr.markForCheck();
  222. try {
  223. const taskData: Omit<RevisionTask, 'id' | 'createdAt'> = {
  224. projectId: this.projectId,
  225. type: this.taskType,
  226. spaceIds: this.selectedSpaces.map(s => s.id),
  227. spaceNames: this.selectedSpaces.map(s => s.name),
  228. estimatedDays: this.estimatedDays === 'custom'
  229. ? `${this.customDays}天`
  230. : this.estimatedDays,
  231. customDays: this.estimatedDays === 'custom' ? this.customDays : undefined,
  232. description: this.description.trim(),
  233. status: 'pending_approval',
  234. createdBy: this.currentUser?.id || '',
  235. createdByName: this.currentUser?.get('name') || '未知用户',
  236. createdByRole: this.currentUser?.get('role') || 'designer'
  237. };
  238. const taskId = await this.revisionTaskService.createRevisionTask(taskData);
  239. // 显示成功提示
  240. if (this.taskType === 'minor') {
  241. window?.fmode?.toast?.success?.('小修改已记录');
  242. } else {
  243. window?.fmode?.toast?.success?.('改图工单已创建,等待组长审批');
  244. }
  245. this.created.emit(taskId);
  246. this.closeModal();
  247. } catch (error) {
  248. console.error('创建工单失败:', error);
  249. window?.fmode?.alert?.('创建工单失败,请重试');
  250. } finally {
  251. this.submitting = false;
  252. this.cdr.markForCheck();
  253. }
  254. }
  255. /**
  256. * 关闭弹窗
  257. */
  258. closeModal(): void {
  259. this.close.emit();
  260. }
  261. /**
  262. * 重置表单
  263. */
  264. private resetForm(): void {
  265. this.taskType = 'major';
  266. this.availableSpaces.forEach(s => s.selected = false);
  267. this.selectedSpaces = [];
  268. this.estimatedDays = '2-3天';
  269. this.customDays = 3;
  270. this.description = '';
  271. this.submitting = false;
  272. this.cdr.markForCheck();
  273. }
  274. }