You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
23 KiB

1 month ago
4 days ago
4 days ago
4 days ago
4 days ago
4 days ago
4 days ago
1 month ago
4 weeks ago
4 days ago
4 days ago
1 month ago
4 days ago
4 days ago
4 days ago
4 days ago
4 days ago
4 days ago
4 days ago
1 month ago
4 days ago
4 days ago
4 days ago
4 days ago
4 days ago
4 days ago
  1. <template>
  2. <div class="screen-wrap">
  3. <div class="top-bar">
  4. <div class="header-left"><img class="site-navbar__brand-logo" src="~@/assets/img/lc.png" alt="龙闯电梯"></div>
  5. <div class="header-center">
  6. <div class="title">生产进度管理看板 · VL2.5升级/线缆COP/机加工</div>
  7. </div>
  8. <div class="tools">
  9. <span class="time">{{ currentTime }}</span>
  10. </div>
  11. </div>
  12. <div class="summary-row">
  13. <div class="summary-card">
  14. <div class="summary-title">VL2.5升级订单</div>
  15. <div class="summary-main">
  16. <span class="summary-rate">{{ renovationKpi.finishRate }}%</span>
  17. <span class="summary-rate-label">完工达成率</span>
  18. </div>
  19. <div class="summary-meta">排产 {{ renovationKpi.total }} · 进行中 {{ renovationKpi.processing }} · 已完成 {{ renovationKpi.finished }}</div>
  20. </div>
  21. <div class="summary-card">
  22. <div class="summary-title">线缆/COP任务</div>
  23. <div class="summary-main">
  24. <span class="summary-rate">{{ cableCopKpi.finishRate }}%</span>
  25. <span class="summary-rate-label">完工达成率</span>
  26. </div>
  27. <div class="summary-meta">排产 {{ cableCopKpi.total }} · 进行中 {{ cableCopKpi.processing }} · 已完成 {{ cableCopKpi.finished }}</div>
  28. </div>
  29. <div class="summary-card">
  30. <div class="summary-title">机加工任务</div>
  31. <div class="summary-main">
  32. <span class="summary-rate">{{ machiningKpi.finishRate }}%</span>
  33. <span class="summary-rate-label">完工达成率</span>
  34. </div>
  35. <div class="summary-meta">排产 {{ machiningKpi.total }} · 进行中 {{ machiningKpi.processing }} · 已完成 {{ machiningKpi.finished }}</div>
  36. </div>
  37. </div>
  38. <div class="legend-row">
  39. <span class="legend-item"><i class="dot done"></i>已完成</span>
  40. <span class="legend-item"><i class="dot todo"></i>未开始</span>
  41. </div>
  42. <div class="board-section">
  43. <div class="section-card section-top">
  44. <div class="section-header">
  45. <span class="section-title">VL2.5升级订单进度</span>
  46. <span class="section-count"> {{ renovationPage + 1 }}/{{ renovationPageCount }} · 显示 {{ displayRenovationList.length }} / {{ renovationList.length }} </span>
  47. </div>
  48. <el-table class="board-table" :data="displayRenovationList" :height="tableHeightTop" border stripe>
  49. <el-table-column type="index" label="序号" width="54" align="center"></el-table-column>
  50. <el-table-column prop="projectNo" label="项目号" min-width="120" align="center"></el-table-column>
  51. <el-table-column prop="floors" label="楼层" min-width="70" align="center"></el-table-column>
  52. <el-table-column prop="planFinishDate" label="计划完工日期" min-width="120" align="center"></el-table-column>
  53. <el-table-column label="仓库配料" width="90" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'stocking')"></span></template></el-table-column>
  54. <el-table-column label="组装" width="84" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'assy')"></span></template></el-table-column>
  55. <el-table-column label="检验" width="84" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'inspect')"></span></template></el-table-column>
  56. <el-table-column label="打包" width="84" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'pack')"></span></template></el-table-column>
  57. <el-table-column prop="status" label="订单状态" width="96" align="center"><template slot-scope="scope"><el-tag class="board-tag" :class="getStatusTagClass(scope.row.status)" size="small">{{ scope.row.status }}</el-tag></template></el-table-column>
  58. <el-table-column prop="finishDate" label="完工时间" width="118" align="center"><template slot-scope="scope">{{ scope.row.finishDate || '-' }}</template></el-table-column>
  59. </el-table>
  60. </div>
  61. <div class="section-card section-bottom-left">
  62. <div class="section-header">
  63. <span class="section-title">线缆/COP任务进度</span>
  64. <span class="section-count"> {{ cableCopPage + 1 }}/{{ cableCopPageCount }} · 显示 {{ displayCableCopList.length }} / {{ cableCopList.length }} </span>
  65. </div>
  66. <el-table class="board-table" :data="displayCableCopList" :height="tableHeightBottom" border stripe>
  67. <el-table-column type="index" label="序号" width="54" align="center"></el-table-column>
  68. <el-table-column prop="taskNo" label="任务单号" min-width="126" align="center"></el-table-column>
  69. <el-table-column prop="taskType" label="类别" min-width="96" align="center">
  70. <template slot-scope="scope">
  71. <el-tag class="board-tag" :class="getTaskTypeClass(scope.row.taskType)" size="small">{{ scope.row.taskType || '-' }}</el-tag>
  72. </template>
  73. </el-table-column>
  74. <el-table-column prop="planFinishDate" label="计划完工日期" min-width="120" align="center"></el-table-column>
  75. <el-table-column prop="taskQty" label="任务数量" min-width="84" align="center"></el-table-column>
  76. <el-table-column prop="reportQty" label="已报工数量" min-width="84" align="center"></el-table-column>
  77. <el-table-column label="线缆生产" width="86" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'lineProduction')"></span></template></el-table-column>
  78. <el-table-column label="COP生产" width="86" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'copProduction')"></span></template></el-table-column>
  79. <el-table-column prop="status" label="任务状态" width="96" align="center">
  80. <template slot-scope="scope">
  81. <el-tag class="board-tag" :class="getStatusTagClass(scope.row.status)" size="small">{{ scope.row.status }}</el-tag>
  82. </template>
  83. </el-table-column>
  84. <el-table-column prop="finishDate" label="完工时间" width="118" align="center"><template slot-scope="scope">{{ scope.row.finishDate || '-' }}</template></el-table-column>
  85. </el-table>
  86. </div>
  87. <div class="section-card section-bottom-right">
  88. <div class="section-header">
  89. <span class="section-title">机加工任务进度</span>
  90. <span class="section-count"> {{ machiningPage + 1 }}/{{ machiningPageCount }} · 显示 {{ displayMachiningList.length }} / {{ machiningList.length }} </span>
  91. </div>
  92. <el-table class="board-table" :data="displayMachiningList" :height="tableHeightBottom" border stripe>
  93. <el-table-column type="index" label="序号" width="54" align="center"></el-table-column>
  94. <el-table-column prop="modelNo" label="物料号" min-width="170" align="center"></el-table-column>
  95. <el-table-column prop="taskQty" label="计划数量" min-width="88" align="center"></el-table-column>
  96. <el-table-column prop="reportQty" label="实际数量" min-width="88" align="center"></el-table-column>
  97. <el-table-column prop="planFinishDate" label="计划完工日期" min-width="120" align="center"></el-table-column>
  98. <el-table-column prop="status" label="任务状态" width="96" align="center">
  99. <template slot-scope="scope">
  100. <el-tag class="board-tag" :class="getStatusTagClass(scope.row.status)" size="small">{{ scope.row.status }}</el-tag>
  101. </template>
  102. </el-table-column>
  103. <el-table-column prop="finishDate" label="实际完工日期" min-width="120" align="center">
  104. <template slot-scope="scope">{{ scope.row.finishDate || '-' }}</template>
  105. </el-table-column>
  106. </el-table>
  107. </div>
  108. </div>
  109. </div>
  110. </template>
  111. <script>
  112. import { getCableCopTaskList, getMachiningTaskList, getRenovationOrderList } from '@/api/longchuang/productionPlan'
  113. import { getScreenInnerHeight } from '@/utils/screenAdapt'
  114. const STATUS_ALLOW_LIST = ['已排产', '进行中', '已完成']
  115. const RENOVATION_NODE_TEMPLATE = ['stocking', 'assy', 'inspect', 'pack']
  116. const CABLE_COP_NODE_TEMPLATE = ['lineProduction', 'copProduction']
  117. const BOARD_PAGE_SIZE = 6
  118. export default {
  119. name: 'ScreenRenovationProgress',
  120. data() {
  121. return {
  122. loading: false,
  123. boardTimerId: null,
  124. tableHeightTop: 220,
  125. tableHeightBottom: 180,
  126. topRowLimit: BOARD_PAGE_SIZE,
  127. bottomRowLimit: BOARD_PAGE_SIZE,
  128. carouselTimerId: null,
  129. carouselIntervalMs: 8000,
  130. renovationPage: 0,
  131. cableCopPage: 0,
  132. machiningPage: 0,
  133. currentTime: '',
  134. timerId: null,
  135. renovationList: [],
  136. cableCopList: [],
  137. machiningList: [],
  138. renovationKpi: { total: 0, processing: 0, finished: 0, finishRate: 0 },
  139. cableCopKpi: { total: 0, processing: 0, finished: 0, finishRate: 0 },
  140. machiningKpi: { total: 0, processing: 0, finished: 0, finishRate: 0 }
  141. }
  142. },
  143. computed: {
  144. renovationPageCount() {
  145. return this.getPageCount(this.renovationList.length, this.topRowLimit)
  146. },
  147. cableCopPageCount() {
  148. return this.getPageCount(this.cableCopList.length, this.bottomRowLimit)
  149. },
  150. machiningPageCount() {
  151. return this.getPageCount(this.machiningList.length, this.bottomRowLimit)
  152. },
  153. displayRenovationList() {
  154. return this.getPageList(this.renovationList, this.renovationPage, this.topRowLimit)
  155. },
  156. displayCableCopList() {
  157. return this.getPageList(this.cableCopList, this.cableCopPage, this.bottomRowLimit)
  158. },
  159. displayMachiningList() {
  160. return this.getPageList(this.machiningList, this.machiningPage, this.bottomRowLimit)
  161. }
  162. },
  163. mounted() {
  164. this.setTableHeight()
  165. this.loadBoardData()
  166. this.updateTime()
  167. this.timerId = setInterval(this.updateTime, 1000)
  168. this.boardTimerId = setInterval(() => {
  169. this.loadBoardData()
  170. }, 60000)
  171. this.startCarousel()
  172. window.addEventListener('resize', this.setTableHeight)
  173. },
  174. beforeDestroy() {
  175. if (this.timerId) clearInterval(this.timerId)
  176. if (this.boardTimerId) clearInterval(this.boardTimerId)
  177. this.stopCarousel()
  178. window.removeEventListener('resize', this.setTableHeight)
  179. },
  180. methods: {
  181. setTableHeight() {
  182. const boardGap = 10
  183. const topRatio = 0.56
  184. const reservedHeight = 286
  185. const sectionHeaderHeight = 46
  186. const boardHeight = Math.max(420, getScreenInnerHeight() - reservedHeight)
  187. const topSectionHeight = Math.floor((boardHeight - boardGap) * topRatio)
  188. const bottomSectionHeight = boardHeight - boardGap - topSectionHeight
  189. this.tableHeightTop = Math.max(120, topSectionHeight - sectionHeaderHeight)
  190. this.tableHeightBottom = Math.max(120, bottomSectionHeight - sectionHeaderHeight)
  191. this.topRowLimit = BOARD_PAGE_SIZE
  192. this.bottomRowLimit = BOARD_PAGE_SIZE
  193. this.normalizeCarouselPage()
  194. },
  195. loadBoardData() {
  196. if (this.loading) return
  197. this.loading = true
  198. const params = { page: 1, limit: 300, statusList: STATUS_ALLOW_LIST }
  199. Promise.all([
  200. getRenovationOrderList(params).catch(() => null),
  201. getCableCopTaskList(params).catch(() => null),
  202. getMachiningTaskList(params).catch(() => null)
  203. ]).then(([renovationRes, cableCopRes, machiningRes]) => {
  204. this.renovationList = this.buildRenovationList(this.getListFromResponse(renovationRes))
  205. this.cableCopList = this.buildCableCopList(this.getListFromResponse(cableCopRes))
  206. this.machiningList = this.buildMachiningList(this.getListFromResponse(machiningRes))
  207. this.renovationKpi = this.buildKpi(this.renovationList)
  208. this.cableCopKpi = this.buildKpi(this.cableCopList)
  209. this.machiningKpi = this.buildKpi(this.machiningList)
  210. this.normalizeCarouselPage()
  211. }).finally(() => {
  212. this.loading = false
  213. })
  214. },
  215. getPageCount(total, pageSize) {
  216. if (!pageSize) return 1
  217. return Math.max(1, Math.ceil(total / pageSize))
  218. },
  219. getPageList(list, pageIndex, pageSize) {
  220. const safeSize = Math.max(1, pageSize || 1)
  221. const count = this.getPageCount((list || []).length, safeSize)
  222. const safePage = Math.min(Math.max(pageIndex, 0), count - 1)
  223. const start = safePage * safeSize
  224. return (list || []).slice(start, start + safeSize)
  225. },
  226. normalizeCarouselPage() {
  227. this.renovationPage = Math.min(this.renovationPage, this.renovationPageCount - 1)
  228. this.cableCopPage = Math.min(this.cableCopPage, this.cableCopPageCount - 1)
  229. this.machiningPage = Math.min(this.machiningPage, this.machiningPageCount - 1)
  230. this.renovationPage = Math.max(this.renovationPage, 0)
  231. this.cableCopPage = Math.max(this.cableCopPage, 0)
  232. this.machiningPage = Math.max(this.machiningPage, 0)
  233. },
  234. nextPage(page, pageCount) {
  235. if (pageCount <= 1) return 0
  236. return (page + 1) % pageCount
  237. },
  238. startCarousel() {
  239. this.stopCarousel()
  240. this.carouselTimerId = setInterval(() => {
  241. this.renovationPage = this.nextPage(this.renovationPage, this.renovationPageCount)
  242. this.cableCopPage = this.nextPage(this.cableCopPage, this.cableCopPageCount)
  243. this.machiningPage = this.nextPage(this.machiningPage, this.machiningPageCount)
  244. }, this.carouselIntervalMs)
  245. },
  246. stopCarousel() {
  247. if (!this.carouselTimerId) return
  248. clearInterval(this.carouselTimerId)
  249. this.carouselTimerId = null
  250. },
  251. getListFromResponse(response) {
  252. const data = response && response.data
  253. const list = data && data.code === 0 && data.page && Array.isArray(data.page.list) ? data.page.list : null
  254. return list || this.getMockList()
  255. },
  256. buildRenovationList(sourceList) {
  257. return (sourceList || [])
  258. .filter(item => STATUS_ALLOW_LIST.includes(item.status))
  259. .map(item => ({
  260. projectNo: item.projectNo || '',
  261. floors: item.floors || '',
  262. planFinishDate: item.planFinishDate || '',
  263. status: item.status || '',
  264. finishDate: item.finishDate || '',
  265. nodeStatusMap: this.toNodeStatusMap(item.nodeList, RENOVATION_NODE_TEMPLATE)
  266. }))
  267. },
  268. buildCableCopList(sourceList) {
  269. return (sourceList || [])
  270. .filter(item => STATUS_ALLOW_LIST.includes(item.status))
  271. .map(item => ({
  272. taskNo: item.taskNo || '',
  273. sourceProjectNo: item.sourceProjectNo || '',
  274. taskType: item.taskType || '',
  275. planFinishDate: item.planFinishDate || '',
  276. status: item.status || '',
  277. finishDate: item.finishDate || '',
  278. taskQty: item.taskQty == null ? 0 : item.taskQty,
  279. reportQty: item.reportQty == null ? 0 : item.reportQty,
  280. nodeStatusMap: this.toNodeStatusMap(item.nodeList, CABLE_COP_NODE_TEMPLATE)
  281. }))
  282. },
  283. buildMachiningList(sourceList) {
  284. return (sourceList || [])
  285. .filter(item => STATUS_ALLOW_LIST.includes(item.status))
  286. .map(item => ({
  287. modelNo: item.modelNo || '',
  288. planFinishDate: item.planFinishDate || '',
  289. status: item.status || '',
  290. finishDate: item.finishDate || '',
  291. taskQty: item.taskQty == null ? 0 : item.taskQty,
  292. reportQty: item.reportQty == null ? 0 : item.reportQty
  293. }))
  294. },
  295. toNodeStatusMap(nodeList, template) {
  296. const map = {}
  297. ;(template || []).forEach(code => { map[code] = '未开始' })
  298. ;(nodeList || []).forEach(node => { map[node.nodeCode] = node.status || '未开始' })
  299. return map
  300. },
  301. buildKpi(list) {
  302. const total = list.length
  303. const processing = list.filter(item => item.status === '进行中').length
  304. const finished = list.filter(item => item.status === '已完成').length
  305. return { total, processing, finished, finishRate: total ? Math.round((finished / total) * 100) : 0 }
  306. },
  307. getNodeCellText(row, code) {
  308. return (row.nodeStatusMap && row.nodeStatusMap[code]) || '未开始'
  309. },
  310. getNodeCellClass(row, code) {
  311. const status = this.getNodeCellText(row, code)
  312. if (status === '已完成') return 'node-chip done'
  313. return 'node-chip todo'
  314. },
  315. getTaskTypeClass(taskType) {
  316. if (taskType === '线缆自制') return 'type-cable'
  317. if (taskType === 'COP自制') return 'type-cop'
  318. return 'type-default'
  319. },
  320. getStatusTagClass(status) {
  321. if (status === '已完成') return 'status-done'
  322. if (status === '进行中') return 'status-doing'
  323. return 'status-planned'
  324. },
  325. updateTime() {
  326. const now = new Date()
  327. const weekList = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
  328. const d = this.dayjs(now)
  329. this.currentTime = `${d.format('YYYY/MM/DD')} ${weekList[now.getDay()]} ${d.format('HH:mm:ss')}`
  330. },
  331. getMockList() {
  332. return []
  333. }
  334. }
  335. }
  336. </script>
  337. <style>
  338. .screen-wrap{height:100vh;padding:16px;background:linear-gradient(165deg,#0a1f36 0%,#0f2b47 50%,#0a2037 100%);display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden}
  339. .top-bar{display:flex;justify-content:space-between;align-items:center;padding:14px 18px;border-radius:12px;border:1px solid rgba(109,167,219,.24);background:rgba(9,29,49,.82);position:relative}
  340. .header-left{display:flex;align-items:center;min-width:110px;z-index:2}
  341. .header-center{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);text-align:center;pointer-events:none;max-width:72%;width:auto;padding:6px 24px 8px;border-radius:8px;border:1px solid rgba(96,170,232,.34);background:linear-gradient(180deg,rgba(33,73,116,.52),rgba(16,44,77,.42))}
  342. .header-center::before{content:'';position:absolute;left:50%;transform:translateX(-50%);top:-8px;width:68%;height:1px;background:linear-gradient(90deg,rgba(87,164,230,0),rgba(87,164,230,.9),rgba(87,164,230,0))}
  343. .top-bar .tools{margin-left:auto;z-index:2}
  344. .title{color:#8fe7ff;font-size:37px;font-weight:800;letter-spacing:2px;line-height:1.1;text-shadow:0 0 14px rgba(79,179,255,.36)}
  345. .tools{display:flex;align-items:center;gap:12px}
  346. .time{color:#89d7ff;font-size:26px;font-weight:600}
  347. .summary-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin:12px 0 8px}
  348. .summary-card{border-radius:10px;padding:10px 14px;background:rgba(14,43,70,.82);border:1px solid rgba(101,157,209,.22)}
  349. .summary-title{color:#b7d3ee;font-size:16px}
  350. .summary-main{display:flex;align-items:baseline;gap:8px;margin-top:6px}
  351. .summary-rate{font-size:39px;font-weight:700;color:#79d5ff;line-height:1}
  352. .summary-rate-label{color:#9dc5e8;font-size:15px}
  353. .summary-meta{margin-top:4px;color:#d4e6f9;font-size:15px;line-height:1.3}
  354. .legend-row{display:flex;gap:16px;margin:0 0 10px 2px}
  355. .legend-item{display:inline-flex;align-items:center;color:#c7dff4;font-size:15px}
  356. .dot{width:10px;height:10px;border-radius:50%;margin-right:6px;display:inline-block}
  357. .dot.done{background:#69e4a4}
  358. .dot.todo{background:#dbe3ee}
  359. .board-section{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:minmax(0,1.1fr) minmax(0,1fr);gap:10px;flex:1;min-height:0}
  360. .section-card{display:flex;flex-direction:column;min-height:0;border-radius:10px;border:1px solid rgba(86,140,190,.35);background:rgba(12,39,64,.96)}
  361. .section-top{grid-column:1 / span 2}
  362. .section-bottom-left{grid-column:1}
  363. .section-bottom-right{grid-column:2}
  364. .section-header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid rgba(80,133,181,.45)}
  365. .section-title{color:#d7ebff;font-size:17px;font-weight:600}
  366. .section-count{color:#9ec6e9;font-size:15px}
  367. .board-table{border-radius:0;overflow:hidden;flex:1;min-height:0}
  368. .board-table .cell{line-height:36px;font-size:16px;height:36px}
  369. .screen-wrap .board-table .el-table,.screen-wrap .board-table .el-table__expanded-cell,.screen-wrap .board-table .el-table__body-wrapper,.screen-wrap .board-table .el-table__empty-block,.screen-wrap .board-table .el-table__fixed-body-wrapper{background:rgba(12,39,64,.96)!important;color:#fff!important}
  370. .screen-wrap .board-table .el-table__header-wrapper th,.screen-wrap .board-table .el-table__fixed-header-wrapper th{background:#123a5e!important;color:#d9e9f8!important;border-color:rgba(80,133,181,.6)!important;font-size:16px!important;padding:12px 0!important}
  371. .screen-wrap .board-table .el-table__body tr>td,.screen-wrap .board-table .el-table__fixed-body-wrapper tr>td,.screen-wrap .board-table .el-table__fixed-right .el-table__fixed-body-wrapper tr>td{background:rgba(20,52,83,.96)!important;border-color:rgba(88,139,187,.4)!important;color:#fff!important;height:48px!important;vertical-align:middle!important}
  372. .screen-wrap .board-table .el-table--striped .el-table__body tr.el-table__row--striped>td,.screen-wrap .board-table .el-table__fixed-body-wrapper tr.el-table__row--striped>td{background:rgba(29,66,102,.96)!important}
  373. .screen-wrap .board-table .el-table--enable-row-hover .el-table__body tr:hover>td,.screen-wrap .board-table .el-table__fixed-body-wrapper tr:hover>td{background:rgba(39,81,123,.96)!important}
  374. .screen-wrap .board-table .el-table .cell{color:#fff!important;line-height:31px!important;overflow:visible!important}
  375. .screen-wrap .board-table .el-table__body-wrapper{scrollbar-width:none;-ms-overflow-style:none}
  376. .screen-wrap .board-table .el-table__body-wrapper::-webkit-scrollbar{width:0;height:0}
  377. .screen-wrap .board-table .el-table__empty-text{color:#9ac2e7!important}
  378. .node-chip{display:inline-block!important;width:46px;height:14px;margin:0 auto;border-radius:2px}
  379. .node-chip.done{background:#6de3a0}
  380. .node-chip.todo{background:#dce4ee}
  381. .board-tag{display:inline-flex!important;align-items:center!important;justify-content:center!important;min-width:88px!important;height:29px!important;padding:0 10px!important;border-radius:14px!important;border:1px solid transparent!important;font-size:14px!important;font-weight:600!important;line-height:27px!important;box-sizing:border-box!important}
  382. .board-tag.type-cable{color:#73cfff!important;background:rgba(28,88,136,.32)!important;border-color:rgba(115,207,255,.45)!important}
  383. .board-tag.type-cop{color:#7ef0c0!important;background:rgba(31,108,89,.32)!important;border-color:rgba(126,240,192,.45)!important}
  384. .board-tag.type-default{color:#d0e5f9!important;background:rgba(80,118,149,.28)!important;border-color:rgba(208,229,249,.34)!important}
  385. .board-tag.status-planned{color:#b9c7d8!important;background:rgba(96,118,141,.28)!important;border-color:rgba(185,199,216,.34)!important}
  386. .board-tag.status-doing{color:#ffd774!important;background:rgba(120,92,27,.32)!important;border-color:rgba(255,215,116,.45)!important}
  387. .board-tag.status-done{color:#83f3be!important;background:rgba(31,110,84,.32)!important;border-color:rgba(131,243,190,.45)!important}
  388. </style>