designer-assignment.component.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. <div class="designer-assignment-container">
  2. <div class="section-header">
  3. <h3>设计师分配</h3>
  4. <div class="assignment-summary">
  5. @if (selectedTeamId) {
  6. <span class="team-info">主要团队:{{ getSelectedTeam()?.name }}</span>
  7. @if (assignmentData.crossTeamCollaborators.length > 0) {
  8. <span class="cross-team-info">跨组合作:{{ assignmentData.crossTeamCollaborators.length }}人</span>
  9. }
  10. }
  11. </div>
  12. </div>
  13. <!-- 精美的设计师分配选择框 -->
  14. <div class="designer-selection-dropdown">
  15. <div class="dropdown-header" (click)="openTeamAssignmentModal()">
  16. <div class="dropdown-content">
  17. @if (selectedTeamId) {
  18. <div class="selected-team-info">
  19. <div class="team-name">{{ getSelectedTeam()?.name }}</div>
  20. <div class="team-summary">
  21. 已分配 {{ getTotalAssignedDesigners() }} 名设计师
  22. @if (assignmentData.crossTeamCollaborators.length > 0) {
  23. ,跨组合作 {{ assignmentData.crossTeamCollaborators.length }} 人
  24. }
  25. </div>
  26. </div>
  27. } @else {
  28. <div class="placeholder-text">
  29. <span class="placeholder-icon">👥</span>
  30. <span>点击选择项目组并分配设计师</span>
  31. </div>
  32. }
  33. </div>
  34. <div class="dropdown-arrow">
  35. <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
  36. <path d="M4 6l4 4 4-4H4z"/>
  37. </svg>
  38. </div>
  39. </div>
  40. </div>
  41. <!-- 设计师组分配弹窗 -->
  42. @if (showTeamAssignmentModal) {
  43. <app-designer-team-assignment-modal
  44. [visible]="showTeamAssignmentModal"
  45. [projectTeams]="projectTeams"
  46. [quotationItems]="quotationItems"
  47. [selectedTeamId]="selectedTeamId"
  48. [selectedDesigners]="assignmentData.quotationAssignments"
  49. [crossTeamCollaborators]="assignmentData.crossTeamCollaborators"
  50. (close)="closeTeamAssignmentModal()"
  51. (confirm)="onModalAssignmentConfirm($event)"
  52. ></app-designer-team-assignment-modal>
  53. }
  54. <!-- 设计师详细日历弹窗 -->
  55. @if (showDesignerCalendar && selectedDesignerForCalendar) {
  56. <div class="calendar-modal-overlay" (click)="closeDesignerCalendar()">
  57. <div class="calendar-modal-container" (click)="$event.stopPropagation()">
  58. <div class="calendar-modal-header">
  59. <h3>{{ selectedDesignerForCalendar.name }} - 详细日历</h3>
  60. <button class="close-btn" (click)="closeDesignerCalendar()">
  61. <svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
  62. <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"/>
  63. </svg>
  64. </button>
  65. </div>
  66. <div class="calendar-modal-body">
  67. <!-- 这里可以集成具体的日历组件 -->
  68. <div class="designer-calendar-placeholder">
  69. <p>设计师详细日历功能正在开发中...</p>
  70. <div class="designer-info-summary">
  71. <h4>{{ selectedDesignerForCalendar.name }}</h4>
  72. <p>团队:{{ selectedDesignerForCalendar.teamName }}</p>
  73. <p>状态:{{ getDesignerStatusText(selectedDesignerForCalendar.status) }}</p>
  74. <p>工作量:{{ selectedDesignerForCalendar.workload }}%</p>
  75. @if (selectedDesignerForCalendar.idleDays > 0) {
  76. <p>已闲置:{{ selectedDesignerForCalendar.idleDays }} 天</p>
  77. }
  78. @if (selectedDesignerForCalendar.reviewDates && selectedDesignerForCalendar.reviewDates.length > 0) {
  79. <p>对图日期:{{ selectedDesignerForCalendar.reviewDates.join(', ') }}</p>
  80. }
  81. </div>
  82. </div>
  83. </div>
  84. </div>
  85. </div>
  86. }
  87. <!-- 自动分配建议 -->
  88. @if (selectedTeamId && getAutoAssignmentSuggestion()) {
  89. <div class="auto-suggestion">
  90. <div class="suggestion-header">
  91. <span class="suggestion-icon">💡</span>
  92. <span>分配建议</span>
  93. </div>
  94. <p>{{ getAutoAssignmentSuggestion() }}</p>
  95. </div>
  96. }
  97. <!-- 报价项目分配 -->
  98. @if (selectedTeamId && quotationItems.length > 0) {
  99. <div class="quotation-assignment-section">
  100. <h4>报价项目分配</h4>
  101. <div class="assignment-grid">
  102. @for (assignment of assignmentData.quotationAssignments; track assignment.quotationItemId) {
  103. <div class="assignment-card">
  104. <div class="assignment-header">
  105. <h5>{{ assignment.quotationItemName }}</h5>
  106. <div class="assigned-count">
  107. 已分配:{{ assignment.assignedDesigners.length }}人
  108. </div>
  109. </div>
  110. <div class="designer-selection">
  111. <div class="available-designers">
  112. <h6>团队成员</h6>
  113. <div class="designer-list">
  114. @for (designer of getSelectedTeam()?.members; track designer.id) {
  115. <div
  116. class="designer-item"
  117. [class.assigned]="assignment.assignedDesigners.includes(designer.id)"
  118. (click)="onDesignerClick(designer)"
  119. >
  120. <div class="designer-avatar">
  121. @if (designer.avatar) {
  122. <img [src]="designer.avatar" [alt]="designer.name" />
  123. } @else {
  124. <div class="avatar-placeholder">{{ designer.name.charAt(0) }}</div>
  125. }
  126. </div>
  127. <div class="designer-info">
  128. <div class="designer-name">
  129. {{ designer.name }}
  130. @if (designer.isTeamLeader) {
  131. <span class="leader-badge">组长</span>
  132. }
  133. </div>
  134. <div class="designer-status">
  135. <span
  136. class="status-dot"
  137. [style.background-color]="getDesignerStatusColor(designer.status)"
  138. ></span>
  139. <span class="status-text">{{ getDesignerStatusText(designer.status) }}</span>
  140. @if (designer.idleDays > 0) {
  141. <span class="idle-days">{{ designer.idleDays }}天未接单</span>
  142. }
  143. </div>
  144. <div class="workload-bar">
  145. <div class="workload-fill" [style.width.%]="designer.workload"></div>
  146. <span class="workload-text">{{ designer.workload }}%</span>
  147. </div>
  148. </div>
  149. <div class="assignment-actions">
  150. @if (assignment.assignedDesigners.includes(designer.id)) {
  151. <button
  152. class="remove-btn"
  153. (click)="removeDesignerFromQuotation(assignment.quotationItemId, designer.id); $event.stopPropagation()"
  154. >
  155. 移除
  156. </button>
  157. } @else {
  158. <button
  159. class="assign-btn"
  160. (click)="assignDesignerToQuotation(assignment.quotationItemId, designer.id); $event.stopPropagation()"
  161. >
  162. 分配
  163. </button>
  164. }
  165. </div>
  166. </div>
  167. }
  168. </div>
  169. </div>
  170. </div>
  171. </div>
  172. }
  173. </div>
  174. </div>
  175. }
  176. <!-- 跨组合作 -->
  177. @if (selectedTeamId) {
  178. <div class="cross-team-section">
  179. <div class="section-title">
  180. <h4>跨组合作</h4>
  181. <button
  182. class="toggle-btn"
  183. (click)="showCrossTeamSelection = !showCrossTeamSelection"
  184. >
  185. @if (showCrossTeamSelection) {
  186. <span>收起</span>
  187. } @else {
  188. <span>添加跨组合作</span>
  189. }
  190. </button>
  191. </div>
  192. <!-- 已选择的跨组合作设计师 -->
  193. @if (assignmentData.crossTeamCollaborators.length > 0) {
  194. <div class="selected-collaborators">
  195. <h5>已选择的跨组合作设计师</h5>
  196. <div class="collaborator-list">
  197. @for (designerId of assignmentData.crossTeamCollaborators; track designerId) {
  198. <div class="collaborator-item">
  199. @if (getDesignerById(designerId); as designer) {
  200. <div class="designer-info">
  201. <span class="designer-name">{{ designer.name }}</span>
  202. <span class="team-name">{{ designer.teamName }}</span>
  203. </div>
  204. <button
  205. class="remove-collaborator-btn"
  206. (click)="removeCrossTeamCollaborator(designerId)"
  207. >
  208. ×
  209. </button>
  210. }
  211. </div>
  212. }
  213. </div>
  214. </div>
  215. }
  216. <!-- 跨组设计师选择 -->
  217. @if (showCrossTeamSelection) {
  218. <div class="cross-team-selection">
  219. <h5>选择其他组设计师</h5>
  220. <div class="cross-team-grid">
  221. @for (team of projectTeams; track team.id) {
  222. @if (team.id !== selectedTeamId) {
  223. <div class="cross-team-group">
  224. <h6>{{ team.name }}</h6>
  225. <div class="designer-list">
  226. @for (designer of team.members; track designer.id) {
  227. <div
  228. class="designer-item"
  229. [class.selected]="assignmentData.crossTeamCollaborators.includes(designer.id)"
  230. (click)="onDesignerClick(designer)"
  231. >
  232. <div class="designer-info">
  233. <span class="designer-name">{{ designer.name }}</span>
  234. <div class="designer-status">
  235. <span
  236. class="status-dot"
  237. [style.background-color]="getDesignerStatusColor(designer.status)"
  238. ></span>
  239. <span class="status-text">{{ getDesignerStatusText(designer.status) }}</span>
  240. </div>
  241. </div>
  242. <div class="selection-actions">
  243. @if (assignmentData.crossTeamCollaborators.includes(designer.id)) {
  244. <button
  245. class="remove-btn"
  246. (click)="removeCrossTeamCollaborator(designer.id); $event.stopPropagation()"
  247. >
  248. 移除
  249. </button>
  250. } @else {
  251. <button
  252. class="add-btn"
  253. (click)="addCrossTeamCollaborator(designer.id); $event.stopPropagation()"
  254. >
  255. 添加
  256. </button>
  257. }
  258. </div>
  259. </div>
  260. }
  261. </div>
  262. </div>
  263. }
  264. }
  265. </div>
  266. </div>
  267. }
  268. </div>
  269. }
  270. <!-- 备注 -->
  271. <div class="notes-section">
  272. <label for="assignmentNotes">分配备注</label>
  273. <textarea
  274. id="assignmentNotes"
  275. [(ngModel)]="assignmentData.notes"
  276. (ngModelChange)="emitAssignmentChange()"
  277. placeholder="请输入分配相关的备注信息..."
  278. class="notes-textarea"
  279. rows="3"
  280. ></textarea>
  281. </div>
  282. <!-- 分配总结 -->
  283. <div class="assignment-summary-section">
  284. <h4>分配总结</h4>
  285. <div class="summary-content">
  286. @if (selectedTeamId) {
  287. <div class="summary-item">
  288. <span class="label">主要团队:</span>
  289. <span class="value">{{ getSelectedTeam()?.name }}</span>
  290. </div>
  291. }
  292. @if (assignmentData.quotationAssignments.length > 0) {
  293. <div class="summary-item">
  294. <span class="label">项目分配:</span>
  295. <div class="assignment-list">
  296. @for (assignment of assignmentData.quotationAssignments; track assignment.quotationItemId) {
  297. @if (assignment.assignedDesigners.length > 0) {
  298. <div class="assignment-summary-item">
  299. <span class="project-name">{{ assignment.quotationItemName }}</span>
  300. <span class="assigned-designers">
  301. @for (designerId of assignment.assignedDesigners; track designerId) {
  302. <span class="designer-tag">{{ getDesignerById(designerId)?.name }}</span>
  303. }
  304. </span>
  305. </div>
  306. }
  307. }
  308. </div>
  309. </div>
  310. }
  311. @if (assignmentData.crossTeamCollaborators.length > 0) {
  312. <div class="summary-item">
  313. <span class="label">跨组合作:</span>
  314. <div class="collaborator-tags">
  315. @for (designerId of assignmentData.crossTeamCollaborators; track designerId) {
  316. <span class="collaborator-tag">{{ getDesignerById(designerId)?.name }}</span>
  317. }
  318. </div>
  319. </div>
  320. }
  321. </div>
  322. </div>
  323. </div>