project-gantt.utils.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. import { PLAN_COLOR_PALETTE } from './project-gantt.constants';
  2. export function createSearchQuery() {
  3. return {
  4. routingName: '',
  5. productName: '',
  6. planCode: ''
  7. };
  8. }
  9. export function createHoverTooltipState() {
  10. return {
  11. visible: false,
  12. content: '',
  13. style: {
  14. left: '0px',
  15. top: '0px'
  16. }
  17. };
  18. }
  19. export function parseDate(value) {
  20. if (!value) {
  21. return null;
  22. }
  23. const date =
  24. value instanceof Date
  25. ? new Date(value)
  26. : new Date(String(value).replace(/-/g, '/'));
  27. if (Number.isNaN(date.getTime())) {
  28. return null;
  29. }
  30. return date;
  31. }
  32. export function startOfDay(date) {
  33. const target = new Date(date);
  34. target.setHours(0, 0, 0, 0);
  35. return target;
  36. }
  37. export function startOfMonth(date) {
  38. return new Date(date.getFullYear(), date.getMonth(), 1);
  39. }
  40. export function endOfMonth(date) {
  41. return new Date(date.getFullYear(), date.getMonth() + 1, 0);
  42. }
  43. export function formatDateKey(date) {
  44. const month = String(date.getMonth() + 1).padStart(2, '0');
  45. const day = String(date.getDate()).padStart(2, '0');
  46. return `${date.getFullYear()}-${month}-${day}`;
  47. }
  48. export function escapeHtml(value) {
  49. return String(value == null ? '' : value)
  50. .replace(/&/g, '&')
  51. .replace(/</g, '&lt;')
  52. .replace(/>/g, '&gt;')
  53. .replace(/"/g, '&quot;')
  54. .replace(/'/g, '&#39;');
  55. }
  56. export function formatDateTime(value) {
  57. if (!value) {
  58. return '';
  59. }
  60. if (typeof value === 'string') {
  61. return value;
  62. }
  63. const date = parseDate(value);
  64. if (!date) {
  65. return '';
  66. }
  67. const month = String(date.getMonth() + 1).padStart(2, '0');
  68. const day = String(date.getDate()).padStart(2, '0');
  69. const hour = String(date.getHours()).padStart(2, '0');
  70. const minute = String(date.getMinutes()).padStart(2, '0');
  71. const second = String(date.getSeconds()).padStart(2, '0');
  72. return `${date.getFullYear()}-${month}-${day} ${hour}:${minute}:${second}`;
  73. }
  74. export function buildCalendarTooltipHtml(entries) {
  75. const list = Array.isArray(entries) ? entries : [entries];
  76. const blocks = list
  77. .map((entry, index) => {
  78. const rows = [
  79. { label: '产品名称', value: entry.productName || '' },
  80. { label: '工艺路线', value: entry.routingName || '' },
  81. {
  82. label: entry.productionOrderNumber ? '生产订单号' : '计划编码',
  83. value: entry.productionOrderNumber || entry.planCode || ''
  84. },
  85. { label: '产品编码', value: entry.productCode || '' },
  86. { label: '数量', value: entry.qty },
  87. { label: '规格', value: entry.specification || '' },
  88. { label: '型号', value: entry.modeType || '' },
  89. { label: '工位', value: entry.resourceName || '' },
  90. { label: '编码', value: entry.resourceCode || '' }
  91. ].filter(
  92. (item) =>
  93. item.value !== '' && item.value !== null && item.value !== undefined
  94. );
  95. return `
  96. <div class="gantt-tooltip-card__section">
  97. ${
  98. list.length > 1
  99. ? `<div class="gantt-tooltip-card__section-title">数据${
  100. index + 1
  101. }</div>`
  102. : ''
  103. }
  104. ${rows
  105. .map(
  106. (item) => `
  107. <div class="gantt-tooltip-card__row">
  108. <span class="gantt-tooltip-card__label">${escapeHtml(
  109. item.label
  110. )}:</span>
  111. <span class="gantt-tooltip-card__value">${escapeHtml(
  112. item.value
  113. )}</span>
  114. </div>
  115. `
  116. )
  117. .join('')}
  118. </div>
  119. `;
  120. })
  121. .join('');
  122. return `
  123. <div class="gantt-tooltip-card">
  124. <div class="gantt-tooltip-card__title">
  125. 工作日历详情${list.length > 1 ? `(${list.length}条)` : ''}
  126. </div>
  127. ${blocks}
  128. </div>
  129. `;
  130. }
  131. export function buildTooltipHtml(
  132. task,
  133. planMetaByCode = {},
  134. activeTab = '',
  135. resourceLabelMode = 'plan'
  136. ) {
  137. const planMeta = planMetaByCode[task.code] || {};
  138. const quantityText = [
  139. task.qty ?? task.productNum ?? planMeta.productNum,
  140. task.measuringUnit || task.unit || planMeta.measuringUnit || planMeta.unit
  141. ]
  142. .filter((item) => item !== '' && item !== null && item !== undefined)
  143. .join('');
  144. const isOrderSchedulingTooltip = resourceLabelMode === 'order';
  145. const orderTitleValue =
  146. task.productionOrderNumber ||
  147. task.apsWorkOrderCode ||
  148. task.workOrderCode ||
  149. task.productionOrderCode ||
  150. planMeta.productionOrderNumber ||
  151. planMeta.apsWorkOrderCode ||
  152. planMeta.workOrderCode ||
  153. task.planCode ||
  154. planMeta.planCode ||
  155. planMeta.code ||
  156. task.code ||
  157. planMeta.productName ||
  158. task.productName ||
  159. '';
  160. const title = isOrderSchedulingTooltip
  161. ? ['订单', orderTitleValue].filter(Boolean).join(':') || '订单信息'
  162. : [task.title, task.name || task.text || planMeta.productName]
  163. .filter(Boolean)
  164. .join(':') ||
  165. task.code ||
  166. '任务信息';
  167. const resourceRows =
  168. activeTab === 'team'
  169. ? [
  170. {
  171. label: '工位',
  172. value: task.resourceName || ''
  173. },
  174. {
  175. label: '编码',
  176. value: task.resourceCode || ''
  177. }
  178. ]
  179. : [];
  180. const rows = [
  181. {
  182. label: '计划编号',
  183. value: planMeta.code || planMeta.planCode || task.code || ''
  184. },
  185. {
  186. label: '开始时间',
  187. value: formatDateTime(
  188. task.rawStartDate || task.start_date || planMeta.startTime
  189. )
  190. },
  191. {
  192. label: '结束时间',
  193. value: formatDateTime(
  194. task.rawEndDate || task.end_date || planMeta.endTime
  195. )
  196. },
  197. {
  198. label: '产品名称',
  199. value: isOrderSchedulingTooltip
  200. ? planMeta.productName || task.productName || ''
  201. : planMeta.productName || task.text || task.name || ''
  202. },
  203. {
  204. label: '数量',
  205. value: quantityText
  206. },
  207. {
  208. label: '工艺路线',
  209. value:
  210. task.routingName ||
  211. planMeta.routingName ||
  212. planMeta.produceRoutingName ||
  213. ''
  214. },
  215. {
  216. label: '规格',
  217. value: planMeta.specification || planMeta.spec || ''
  218. },
  219. {
  220. label: '型号',
  221. value: task.modeType || planMeta.modeType || planMeta.model || ''
  222. },
  223. {
  224. label: '批次号',
  225. value:
  226. task.batchNo ||
  227. task.batchNumber ||
  228. task.batchCode ||
  229. planMeta.batchNo ||
  230. planMeta.batchNumber ||
  231. planMeta.batchCode ||
  232. ''
  233. },
  234. ...resourceRows,
  235. ...(resourceLabelMode === 'order'
  236. ? []
  237. : [
  238. {
  239. label: activeTab === 'factory' ? '工厂' : '班组',
  240. value:
  241. task.teamName ||
  242. planMeta.teamName ||
  243. planMeta.executionTeamName ||
  244. ''
  245. }
  246. ])
  247. ].filter((item) => item.value);
  248. return `
  249. <div class="gantt-tooltip-card">
  250. <div class="gantt-tooltip-card__title">${escapeHtml(title)}</div>
  251. ${rows
  252. .map(
  253. (item) => `
  254. <div class="gantt-tooltip-card__row">
  255. <span class="gantt-tooltip-card__label">${escapeHtml(
  256. item.label
  257. )}:</span>
  258. <span class="gantt-tooltip-card__value">${escapeHtml(
  259. item.value
  260. )}</span>
  261. </div>
  262. `
  263. )
  264. .join('')}
  265. </div>
  266. `;
  267. }
  268. export function resolveTaskColor(type) {
  269. if (type == 1) return '#02a7f0';
  270. if (type == 2) return '#fec0dc';
  271. if (type == 3) return '#62ddd4';
  272. if (type == 4) return '#d1a6ff';
  273. if (type == 5) return '#0e85fa';
  274. return '#8fb7ff';
  275. }
  276. export function hashString(value) {
  277. const text = String(value || '');
  278. let hash = 0;
  279. for (let i = 0; i < text.length; i++) {
  280. hash = (hash << 5) - hash + text.charCodeAt(i);
  281. hash |= 0;
  282. }
  283. return Math.abs(hash);
  284. }
  285. export function resolvePlanColor(planKey) {
  286. if (!planKey) {
  287. return PLAN_COLOR_PALETTE[0];
  288. }
  289. return PLAN_COLOR_PALETTE[hashString(planKey) % PLAN_COLOR_PALETTE.length];
  290. }