SelectedMaterialDrawer.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <template>
  2. <el-drawer
  3. :append-to-body="true"
  4. :model-value="modelValue"
  5. :show-close="false"
  6. direction="rtl"
  7. :size="computedSize"
  8. class="selected-material-drawer"
  9. @update:model-value="emit('update:modelValue', $event)">
  10. <template #header>
  11. <div class="drawer-header">
  12. <div class="drawer-header__main">
  13. <div class="drawer-header__icon">
  14. <Icon icon="ep:goods" :size="22" />
  15. </div>
  16. <div>
  17. <div class="drawer-title">{{ t('bomList.materialDetail') }}</div>
  18. <div class="drawer-subtitle">查看当前维修项目关联的物料明细</div>
  19. </div>
  20. </div>
  21. <el-button circle @click="handleClose">
  22. <Icon icon="ep:close" />
  23. </el-button>
  24. </div>
  25. </template>
  26. <div class="drawer-body">
  27. <section class="material-section">
  28. <div class="section-header">
  29. <div class="section-title">
  30. <span class="section-marker"></span>
  31. <span>关联物料</span>
  32. </div>
  33. <span class="material-total">共 {{ filteredMaterials.length }} 条</span>
  34. </div>
  35. <div class="table-container">
  36. <ZmTable
  37. :data="filteredMaterials"
  38. :loading="loading"
  39. :show-border="true"
  40. settings-cache-key="pms-maintain-selected-material">
  41. <ZmTableColumn
  42. v-if="!hideExtraColumns"
  43. prop="factory"
  44. :label="t('workOrderMaterial.factory')"
  45. min-width="140" />
  46. <ZmTableColumn
  47. v-if="!hideExtraColumns"
  48. prop="costCenter"
  49. :label="t('workOrderMaterial.costCenter')"
  50. min-width="150" />
  51. <ZmTableColumn
  52. v-if="!hideExtraColumns"
  53. prop="projectDepartment"
  54. :label="t('workOrderMaterial.storageLocation')"
  55. min-width="150" />
  56. <ZmTableColumn
  57. prop="materialName"
  58. :label="t('workOrderMaterial.materialName')"
  59. min-width="180" />
  60. <ZmTableColumn
  61. prop="materialCode"
  62. :label="t('workOrderMaterial.materialCode')"
  63. min-width="150" />
  64. <ZmTableColumn prop="unit" :label="t('workOrderMaterial.unit')" width="100" />
  65. <ZmTableColumn
  66. prop="unitPrice"
  67. :label="t('workOrderMaterial.unitPrice')"
  68. min-width="120" />
  69. <ZmTableColumn
  70. prop="quantity"
  71. :label="t('workOrderMaterial.ConsumptionQuantity')"
  72. min-width="130" />
  73. <ZmTableColumn prop="materialSource" :label="t('bomList.type')" min-width="120" />
  74. <ZmTableColumn
  75. v-if="!detail"
  76. :label="t('workplace.operation')"
  77. width="100"
  78. fixed="right"
  79. action>
  80. <template #default="{ row }">
  81. <el-button link type="danger" @click="handleDelete(row)">
  82. <Icon icon="ep:delete" class="mr-4px" />{{ t('form.delete') }}
  83. </el-button>
  84. </template>
  85. </ZmTableColumn>
  86. </ZmTable>
  87. </div>
  88. </section>
  89. </div>
  90. <template #footer>
  91. <div class="drawer-footer">
  92. <el-button @click="handleClose">关闭</el-button>
  93. </div>
  94. </template>
  95. </el-drawer>
  96. </template>
  97. <script setup lang="ts">
  98. import { useTableComponents } from '@/components/ZmTable/useTableComponents'
  99. interface MaterialRow {
  100. id?: number
  101. bomNodeId?: number | string
  102. factory?: string
  103. costCenter?: string
  104. projectDepartment?: string
  105. materialName?: string
  106. materialCode?: string
  107. unit?: string
  108. unitPrice?: number
  109. quantity?: number
  110. materialSource?: string
  111. }
  112. defineOptions({ name: 'SelectedMaterialDrawer' })
  113. const props = withDefaults(
  114. defineProps<{
  115. modelValue: boolean
  116. nodeId?: number | string
  117. detail?: boolean
  118. materials?: MaterialRow[]
  119. hideExtraColumns?: boolean
  120. }>(),
  121. {
  122. detail: false,
  123. materials: () => [],
  124. hideExtraColumns: false
  125. }
  126. )
  127. const emit = defineEmits<{
  128. (e: 'update:modelValue', value: boolean): void
  129. (e: 'add', row: MaterialRow): void
  130. (e: 'delete', row: MaterialRow): void
  131. }>()
  132. const { t } = useI18n()
  133. const message = useMessage()
  134. const { ZmTable, ZmTableColumn } = useTableComponents<MaterialRow>()
  135. const loading = ref(false)
  136. const windowWidth = ref(window.innerWidth)
  137. const computedSize = computed(() => {
  138. if (windowWidth.value <= 768) return '100%'
  139. return windowWidth.value > 1440 ? '68%' : '82%'
  140. })
  141. const filteredMaterials = computed(() => {
  142. if (!props.nodeId) return []
  143. return props.materials.filter((item) => item.bomNodeId === props.nodeId)
  144. })
  145. const handleDelete = async (row: MaterialRow) => {
  146. try {
  147. await message.delConfirm()
  148. emit('delete', row)
  149. } catch {}
  150. }
  151. const handleClose = () => {
  152. emit('update:modelValue', false)
  153. }
  154. const openDrawer = () => {
  155. emit('update:modelValue', true)
  156. }
  157. const closeDrawer = () => {
  158. handleClose()
  159. }
  160. const updateWindowWidth = () => {
  161. windowWidth.value = window.innerWidth
  162. }
  163. onMounted(() => window.addEventListener('resize', updateWindowWidth))
  164. onUnmounted(() => window.removeEventListener('resize', updateWindowWidth))
  165. defineExpose({ openDrawer, closeDrawer })
  166. </script>
  167. <style scoped>
  168. .drawer-header {
  169. display: flex;
  170. align-items: center;
  171. justify-content: space-between;
  172. gap: 16px;
  173. width: 100%;
  174. }
  175. .drawer-header__main {
  176. display: flex;
  177. align-items: center;
  178. min-width: 0;
  179. }
  180. .drawer-header__icon {
  181. display: flex;
  182. align-items: center;
  183. justify-content: center;
  184. width: 44px;
  185. height: 44px;
  186. margin-right: 12px;
  187. color: var(--el-color-primary);
  188. background: var(--el-color-primary-light-9);
  189. border: 1px solid var(--el-color-primary-light-7);
  190. border-radius: 8px;
  191. }
  192. .drawer-title {
  193. font-size: 18px;
  194. font-weight: 600;
  195. color: var(--el-text-color-primary);
  196. }
  197. .drawer-subtitle {
  198. margin-top: 4px;
  199. font-size: 13px;
  200. color: var(--el-text-color-secondary);
  201. }
  202. .drawer-body {
  203. height: 100%;
  204. padding: 4px;
  205. }
  206. .material-section {
  207. height: 100%;
  208. overflow: hidden;
  209. background: var(--el-bg-color);
  210. border: 1px solid var(--el-border-color-lighter);
  211. border-radius: 8px;
  212. }
  213. .section-header {
  214. display: flex;
  215. align-items: center;
  216. justify-content: space-between;
  217. min-height: 54px;
  218. padding: 0 18px;
  219. background: var(--el-fill-color-extra-light);
  220. border-bottom: 1px solid var(--el-border-color-lighter);
  221. }
  222. .section-title {
  223. display: flex;
  224. align-items: center;
  225. font-size: 16px;
  226. font-weight: 600;
  227. color: var(--el-text-color-primary);
  228. }
  229. .section-marker {
  230. width: 4px;
  231. height: 18px;
  232. margin-right: 10px;
  233. background: var(--el-color-primary);
  234. border-radius: 2px;
  235. }
  236. .material-total {
  237. padding: 4px 10px;
  238. font-size: 12px;
  239. color: var(--el-color-primary);
  240. background: var(--el-color-primary-light-9);
  241. border-radius: 4px;
  242. }
  243. .table-container {
  244. padding: 16px;
  245. }
  246. .drawer-footer {
  247. display: flex;
  248. justify-content: flex-end;
  249. }
  250. @media (width <= 768px) {
  251. .drawer-subtitle {
  252. display: none;
  253. }
  254. .table-container {
  255. padding: 12px;
  256. }
  257. }
  258. </style>