PurchaseDetail.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. <script setup lang="ts">
  2. import { ref, reactive, nextTick, computed } from 'vue'
  3. import Drawer from '@/components/Drawer/index.vue'
  4. import type { FormInstance, FormRules } from 'element-plus'
  5. import { ColumnProps } from '@/components/TableBase/interface/index'
  6. import { generateRandom } from '@/utils/common'
  7. import { ElMessage } from 'element-plus'
  8. import * as XLSX from 'xlsx'
  9. const isNew = ref(true)
  10. const tableData = ref<any[]>([])
  11. const formLabelWidth = ref('140px')
  12. const ruleFormRef = ref<FormInstance>()
  13. const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
  14. const form = ref({
  15. id: '',
  16. T_name:'',
  17. T_model:'',
  18. T_spec:'',
  19. T_quantity: null as number | null,
  20. T_demand:'',
  21. T_remark:'',
  22. T_state:1,
  23. T_date:'',
  24. T_unit_price: null as number | null,
  25. T_amount: null as number | null,
  26. T_reference_site:'',
  27. T_reference_site_title:'',
  28. T_bit_number:'',
  29. T_packaging:'',
  30. })
  31. // 验证整数
  32. const validateInteger = (rule: any, value: any, callback: any) => {
  33. if (value === '' || value === null || value === undefined) {
  34. callback()
  35. return
  36. }
  37. const num = Number(value)
  38. if (isNaN(num) || !Number.isInteger(num)) {
  39. callback(new Error('请输入整数'))
  40. } else if (num < 0) {
  41. callback(new Error('数量不能为负数'))
  42. } else {
  43. callback()
  44. }
  45. }
  46. // 验证小数(正数)
  47. const validateDecimal = (rule: any, value: any, callback: any) => {
  48. if (value === '' || value === null || value === undefined) {
  49. callback()
  50. return
  51. }
  52. const num = Number(value)
  53. if (isNaN(num)) {
  54. callback(new Error('请输入有效的数字'))
  55. } else if (num < 0) {
  56. callback(new Error('价格不能为负数'))
  57. } else {
  58. callback()
  59. }
  60. }
  61. const rules = reactive<FormRules>({
  62. T_name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
  63. T_quantity: [
  64. { required: true, message: '请输入数量', trigger: 'blur' },
  65. { validator: validateInteger, trigger: 'blur' }
  66. ],
  67. T_unit_price: [
  68. { validator: validateDecimal, trigger: 'blur' }
  69. ],
  70. T_amount: [
  71. { validator: validateDecimal, trigger: 'blur' }
  72. ]
  73. })
  74. const columns: ColumnProps[] = [
  75. { type: 'index', label: '序号', width: 80, align: 'center' },
  76. { prop: 'T_name', label: '名称', align: 'center' },
  77. { prop: 'T_bit_number', label: '位号', align: 'center', width: 100 },
  78. { prop: 'T_packaging', label: '封装', align: 'center', width: 100 },
  79. { prop: 'T_model', label: '型号', align: 'center', width: 100 },
  80. { prop: 'T_spec', label: '规格', align: 'center', width: 100 },
  81. { prop: 'T_quantity', label: '数量', align: 'center'},
  82. { prop: 'T_demand', label: '需求', align: 'center', width: 140 },
  83. { prop: 'T_date', label: '采购时间', align: 'center', width: 150 },
  84. { prop: 'T_unit_price', label: '采购单价', align: 'center', width: 120},
  85. { prop: 'T_amount', label: '采购金额', align: 'center', width: 120},
  86. { prop: 'T_reference_site', label: '参考网址', align: 'center', width: 140 },
  87. { prop: 'T_remark', label: '备注', align: 'center', width: 140 },
  88. { prop: 'T_state', label: '状态', align: 'center', width: 120 },
  89. { prop: 'operation', label: '操作', width: 160, fixed: 'right', align: 'center' }
  90. ]
  91. const openProductionDetailed = (type: string, row?: any) => {
  92. isNew.value = type === 'new' ? true : false
  93. if (!isNew.value) {
  94. form.value = { ...row }
  95. }
  96. drawerRef.value?.openDrawer()
  97. }
  98. const callbackDrawer = (done: () => void) => {
  99. done()
  100. resetForm(ruleFormRef.value)
  101. }
  102. const resetForm = (formEl: FormInstance | undefined) => {
  103. if (!formEl) return
  104. formEl.resetFields()
  105. }
  106. const deletePurchaseDetail = (id: string) => {
  107. tableData.value = tableData.value.filter((item: any) => item.id !== id)
  108. emit('onPlanning', tableData.value)
  109. }
  110. const addPurchaseDetail = (formEl: FormInstance | undefined) => {
  111. if (!formEl) return
  112. formEl.validate(valid => {
  113. if (valid) {
  114. // 确保数据类型正确
  115. const formattedData = {
  116. ...form.value,
  117. T_quantity: form.value.T_quantity ? parseInt(form.value.T_quantity.toString()) : 0,
  118. T_unit_price: form.value.T_unit_price ? parseFloat(form.value.T_unit_price.toString()) : 0,
  119. T_amount: form.value.T_amount ? parseFloat(form.value.T_amount.toString()) : 0
  120. }
  121. if (isNew.value) {
  122. tableData.value.push({ ...formattedData, id: generateRandom() })
  123. } else {
  124. const index = tableData.value.findIndex(item => item.id === form.value.id)
  125. tableData.value[index] = { ...formattedData }
  126. }
  127. nextTick(() => {
  128. isNew.value = true
  129. drawerRef.value?.closeDrawer()
  130. resetForm(ruleFormRef.value)
  131. emit('onPlanning', tableData.value)
  132. })
  133. }
  134. })
  135. }
  136. const emit = defineEmits<{ (event: 'onPlanning', value: any): void }>()
  137. const getDetailInfo = () => tableData.value
  138. const clearDetail = () => (tableData.value = [])
  139. const setDetailData = (info: any[]) => {
  140. tableData.value = info.map((item: any) => {
  141. item.id = generateRandom()
  142. return item
  143. })
  144. }
  145. defineExpose({
  146. getDetailInfo,
  147. clearDetail,
  148. setDetailData
  149. })
  150. const props = defineProps<{ disabled: boolean; isShow?: string;typeTip?:string }>()
  151. const disabled = computed(() => props.disabled)
  152. const isShow = ref(props.isShow)
  153. const typeTip = ref(props.typeTip)
  154. // 导入Excel文件
  155. const importDialogVisible = ref(false)
  156. const fileInputRef = ref<HTMLInputElement | null>(null)
  157. const uploadFileList = ref<any[]>([])
  158. const tempImportData = ref<any[]>([]) // 临时存储解析的数据
  159. const handleImportExcel = () => {
  160. importDialogVisible.value = true
  161. uploadFileList.value = []
  162. tempImportData.value = []
  163. }
  164. // 下载模板
  165. const handleDownloadTemplate = () => {
  166. const link = document.createElement('a')
  167. link.href = '/采购申请模版.xlsx'
  168. link.download = '采购申请模版.xlsx'
  169. link.click()
  170. ElMessage.success('模板下载成功')
  171. }
  172. // 解析Excel文件
  173. const parseExcelFile = (file: File) => {
  174. const reader = new FileReader()
  175. reader.onload = (e) => {
  176. try {
  177. const data = e.target?.result
  178. const workbook = XLSX.read(data, { type: 'array' })
  179. // 读取第一个sheet
  180. const firstSheetName = workbook.SheetNames[0]
  181. const worksheet = workbook.Sheets[firstSheetName]
  182. // 将sheet转换为JSON
  183. const jsonData: any[] = XLSX.utils.sheet_to_json(worksheet, { header: 1 })
  184. // 辅助函数:解码HTML实体
  185. const decodeHTMLEntities = (text: string): string => {
  186. const textarea = document.createElement('textarea')
  187. textarea.innerHTML = text
  188. return textarea.value
  189. }
  190. // 辅助函数:获取单元格超链接
  191. const getCellHyperlink = (worksheet: any, rowIndex: number, colIndex: number): string => {
  192. // 将列索引转换为Excel列字母(0->A, 1->B, ..., 10->K)
  193. const colLetter = String.fromCharCode(65 + colIndex)
  194. // Excel行号从1开始,但我们的数据从第2行开始(索引1对应Excel的第2行)
  195. const cellAddress = `${colLetter}${rowIndex + 1}`
  196. const cell = worksheet[cellAddress]
  197. // 检查单元格是否有超链接
  198. if (cell && cell.l && cell.l.Target) {
  199. // 解码HTML实体,将 &amp; 转换回 &
  200. return decodeHTMLEntities(cell.l.Target)
  201. }
  202. // 如果没有超链接,返回单元格的文本值
  203. // return cell ? (cell.v || '') : ''
  204. return ''
  205. }
  206. // 解析数据(从第2行开始,跳过标题行)
  207. const parsedData: any[] = []
  208. for (let i = 1; i < jsonData.length; i++) {
  209. const row = jsonData[i]
  210. if (!row || row.length === 0) continue
  211. // 获取参考网址的超链接(第11列,索引为10)
  212. const referenceSite = getCellHyperlink(worksheet, i, 10)
  213. // 数据类型转换
  214. const quantity = row[5] ? parseInt(row[5].toString()) : 0
  215. const unitPrice = row[8] ? parseFloat(row[8].toString()) : 0
  216. const amount = row[9] ? parseFloat(row[9].toString()) : 0
  217. // 根据Excel列映射到表单字段
  218. const item = {
  219. id: generateRandom(),
  220. T_name: row[1] || '', // 名称
  221. T_bit_number: row[2] || '', // 位号
  222. T_packaging: row[3] || '', // 封装
  223. T_model: '', // 型号
  224. T_spec: row[4] || '', // 规格
  225. T_quantity: quantity, // 数量(整数)
  226. T_demand: (row[6] !== undefined && row[6] !== null) ? row[6].toString() : '', // 需求(转换为字符串)
  227. T_unit_price: unitPrice, // 采购单价(小数)
  228. T_amount: amount, // 采购金额(小数)
  229. T_reference_site: referenceSite, // 参考网址(超链接)
  230. T_reference_site_title: row[10] || '', // 参考网址标题
  231. T_remark: row[11] || '', // 备注
  232. T_state: 1, // 状态:待采购
  233. T_date: '' // 采购时间
  234. }
  235. parsedData.push(item)
  236. }
  237. if (parsedData.length > 0) {
  238. tempImportData.value = parsedData
  239. ElMessage.success(`文件解析成功,共 ${parsedData.length} 条有效数据`)
  240. } else {
  241. ElMessage.warning('未找到有效数据')
  242. }
  243. } catch (error) {
  244. console.error('Excel解析错误:', error)
  245. ElMessage.error('Excel文件解析失败,请检查文件格式')
  246. }
  247. }
  248. reader.onerror = () => {
  249. ElMessage.error('文件读取失败')
  250. }
  251. reader.readAsArrayBuffer(file)
  252. }
  253. // 文件列表改变
  254. const handleFileChange = (file: any, fileList: any[]) => {
  255. uploadFileList.value = fileList
  256. // 当文件被选中时,立即解析
  257. if (file && file.raw) {
  258. const isExcel = file.raw.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
  259. file.raw.type === 'application/vnd.ms-excel'
  260. if (!isExcel) {
  261. ElMessage.error('只能上传Excel文件!')
  262. uploadFileList.value = []
  263. return
  264. }
  265. parseExcelFile(file.raw)
  266. }
  267. }
  268. // 提交导入
  269. const handleSubmitImport = () => {
  270. if (tempImportData.value.length === 0) {
  271. ElMessage.warning('请先上传Excel文件')
  272. return
  273. }
  274. // 将解析的数据添加到表格
  275. tableData.value.push(...tempImportData.value)
  276. ElMessage.success(`成功导入 ${tempImportData.value.length} 条数据`)
  277. emit('onPlanning', tableData.value)
  278. // 关闭对话框并清空数据
  279. importDialogVisible.value = false
  280. uploadFileList.value = []
  281. tempImportData.value = []
  282. }
  283. // 批量设置采购时间
  284. const batchDateDialogVisible = ref(false)
  285. const batchDate = ref('')
  286. const handleBatchSetDate = () => {
  287. batchDateDialogVisible.value = true
  288. batchDate.value = ''
  289. }
  290. const confirmBatchSetDate = () => {
  291. if (!batchDate.value) {
  292. ElMessage.warning('请选择日期')
  293. return
  294. }
  295. tableData.value.forEach((item: any) => {
  296. item.T_date = batchDate.value
  297. })
  298. ElMessage.success('批量设置成功')
  299. emit('onPlanning', tableData.value)
  300. batchDateDialogVisible.value = false
  301. }
  302. // 处理表格内数据变化
  303. const handleCellValueChange = (row: any, field: string, value: any) => {
  304. row[field] = value
  305. emit('onPlanning', tableData.value)
  306. }
  307. // 格式化数字显示,0值显示为空
  308. const formatNumberDisplay = (value: any) => {
  309. if (value === 0 || value === '0' || value === null || value === undefined) {
  310. return ''
  311. }
  312. return value
  313. }
  314. </script>
  315. <template>
  316. <el-table
  317. stripe
  318. :data="tableData"
  319. style="width: 100%"
  320. :header-cell-style="{
  321. background: 'rgb(225 226 228)',
  322. color: '#000'
  323. }"
  324. >
  325. <template v-for="item in columns" :key="item.prop">
  326. <!-- 状态列 -->
  327. <el-table-column
  328. v-if="item.prop === 'T_state'"
  329. :label="item.label"
  330. :width="item.width"
  331. align="center"
  332. >
  333. <template v-slot="scope">
  334. <template v-if="isShow !== 'myPurchase' && typeTip !== 'view'">
  335. <el-select
  336. v-model="scope.row.T_state"
  337. size="small"
  338. style="width: 100%"
  339. @change="handleCellValueChange(scope.row, 'T_state', scope.row.T_state)"
  340. >
  341. <el-option :label="'待采购'" :value="1" />
  342. <el-option :label="'已采购'" :value="2" />
  343. </el-select>
  344. </template>
  345. <template v-else>
  346. <el-text v-if="scope.row.T_state === 1" effect="dark">待采购</el-text>
  347. <el-text v-else type="success" effect="dark">已采购</el-text>
  348. </template>
  349. </template>
  350. </el-table-column>
  351. <el-table-column
  352. v-else-if="item.prop === 'T_reference_site'"
  353. :label="item.label"
  354. :width="item.width"
  355. align="center"
  356. >
  357. <template v-slot="scope">
  358. <!-- 如果有链接地址,显示为可点击链接 -->
  359. <a
  360. v-if="scope.row.T_reference_site"
  361. :href="scope.row.T_reference_site"
  362. target="_blank"
  363. style="color: #409eff; text-decoration: underline;"
  364. >
  365. {{ scope.row.T_reference_site_title || '参考网址' }}
  366. </a>
  367. <!-- 如果没有链接地址但有标题,显示纯文本 -->
  368. <span v-else-if="scope.row.T_reference_site_title">{{ scope.row.T_reference_site_title }}</span>
  369. <!-- 两者都没有,显示 - -->
  370. <span v-else>-</span>
  371. </template>
  372. </el-table-column>
  373. <!-- 采购时间可编辑列 -->
  374. <el-table-column
  375. v-else-if="item.prop === 'T_date' && isShow !== 'myPurchase'"
  376. :width="item.width"
  377. align="center"
  378. >
  379. <template #header>
  380. <span style="cursor: pointer; color: #409eff" @click="handleBatchSetDate" title="点击批量设置时间">
  381. {{ item.label }}
  382. </span>
  383. </template>
  384. <template v-slot="scope">
  385. <el-date-picker
  386. v-model="scope.row.T_date"
  387. type="date"
  388. placeholder="采购时间"
  389. format="YYYY-MM-DD"
  390. value-format="YYYY-MM-DD"
  391. size="small"
  392. style="width: 100%"
  393. :disabled="typeTip === 'view'"
  394. @change="handleCellValueChange(scope.row, 'T_date', scope.row.T_date)"
  395. />
  396. </template>
  397. </el-table-column>
  398. <!-- 采购单价可编辑列 -->
  399. <el-table-column
  400. v-else-if="item.prop === 'T_unit_price' && isShow !== 'myPurchase'"
  401. :label="item.label"
  402. :width="item.width"
  403. align="center"
  404. >
  405. <template v-slot="scope">
  406. <el-input-number
  407. v-model="scope.row.T_unit_price"
  408. :min="0"
  409. :precision="2"
  410. :controls="false"
  411. size="small"
  412. style="width: 100%; text-align: left"
  413. :disabled="typeTip === 'view'"
  414. :placeholder="scope.row.T_unit_price === 0 ? '' : '请输入单价'"
  415. @change="handleCellValueChange(scope.row, 'T_unit_price', scope.row.T_unit_price)"
  416. @blur="scope.row.T_unit_price === 0 && (scope.row.T_unit_price = null)"
  417. @focus="scope.row.T_unit_price === null && (scope.row.T_unit_price = 0)"
  418. />
  419. </template>
  420. </el-table-column>
  421. <!-- 采购金额可编辑列 -->
  422. <el-table-column
  423. v-else-if="item.prop === 'T_amount' && isShow !== 'myPurchase'"
  424. :label="item.label"
  425. :width="item.width"
  426. align="center"
  427. >
  428. <template v-slot="scope">
  429. <el-input-number
  430. v-model="scope.row.T_amount"
  431. :min="0"
  432. :precision="2"
  433. :controls="false"
  434. size="small"
  435. style="width: 100%; text-align: left"
  436. :disabled="typeTip === 'view'"
  437. :placeholder="scope.row.T_amount === 0 ? '' : '请输入金额'"
  438. @change="handleCellValueChange(scope.row, 'T_amount', scope.row.T_amount)"
  439. @blur="scope.row.T_amount === 0 && (scope.row.T_amount = null)"
  440. @focus="scope.row.T_amount === null && (scope.row.T_amount = 0)"
  441. />
  442. </template>
  443. </el-table-column>
  444. <!-- 备注可编辑列 -->
  445. <el-table-column
  446. v-else-if="item.prop === 'T_remark' && isShow !== 'myPurchase'"
  447. :label="item.label"
  448. :width="item.width"
  449. align="center"
  450. >
  451. <template v-slot="scope">
  452. <el-input
  453. v-model="scope.row.T_remark"
  454. type="text"
  455. placeholder="请输入备注"
  456. size="small"
  457. :disabled="typeTip === 'view'"
  458. @change="handleCellValueChange(scope.row, 'T_remark', scope.row.T_remark)"
  459. />
  460. </template>
  461. </el-table-column>
  462. <el-table-column show-overflow-tooltip v-bind="item" v-else-if="item.type === 'index'"></el-table-column>
  463. <el-table-column show-overflow-tooltip v-bind="item" v-else-if="item.fixed !== 'right' && item.type !== 'index'"> </el-table-column>
  464. <el-table-column show-overflow-tooltip v-bind="item" v-else-if="item.fixed === 'right' && isShow === 'myPurchase' && typeTip !== 'view'">
  465. <template #default="{ row }" >
  466. <el-button size="small" type="primary" @click="openProductionDetailed('edit', row)"
  467. >编辑</el-button
  468. >
  469. <el-button size="small" type="danger" @click="deletePurchaseDetail(row.id)"
  470. >删除</el-button>
  471. </template>
  472. </el-table-column>
  473. </template>
  474. <template #append v-if="isShow === 'myPurchase'">
  475. <el-button type="primary" :disabled="disabled" @click="openProductionDetailed('new')">
  476. <el-icon><Plus /></el-icon><span style="margin-left: 6px">添加</span>
  477. </el-button>
  478. <el-button type="success" :disabled="disabled" @click="handleImportExcel" style="margin-left: 10px">
  479. <el-icon><Plus /></el-icon><span style="margin-left: 6px">导入Excel</span>
  480. </el-button>
  481. </template>
  482. </el-table>
  483. <!-- 导入Excel对话框 -->
  484. <el-dialog
  485. v-model="importDialogVisible"
  486. title="导入Excel数据"
  487. width="500px"
  488. :close-on-click-modal="false"
  489. >
  490. <div style="margin-bottom: 20px">
  491. <el-alert
  492. title="请先下载模板,按照模板格式填写数据后上传"
  493. type="info"
  494. :closable="false"
  495. show-icon
  496. />
  497. </div>
  498. <div style="margin-bottom: 20px; text-align: center">
  499. <el-button type="primary" @click="handleDownloadTemplate">
  500. <el-icon><Download /></el-icon>
  501. <span style="margin-left: 6px">下载模板</span>
  502. </el-button>
  503. </div>
  504. <el-upload
  505. drag
  506. :file-list="uploadFileList"
  507. :on-change="handleFileChange"
  508. :auto-upload="false"
  509. accept=".xlsx,.xls"
  510. :limit="1"
  511. >
  512. <el-icon class="el-icon--upload"><upload-filled /></el-icon>
  513. <div class="el-upload__text">
  514. 将文件拖到此处,或<em>点击上传</em>
  515. </div>
  516. <template #tip>
  517. <div class="el-upload__tip">
  518. 只能上传 xlsx/xls 文件
  519. </div>
  520. </template>
  521. </el-upload>
  522. <template #footer>
  523. <span class="dialog-footer">
  524. <el-button type="primary" @click="handleSubmitImport">提交</el-button>
  525. <el-button @click="importDialogVisible = false">取消</el-button>
  526. </span>
  527. </template>
  528. </el-dialog>
  529. <!-- 批量设置采购时间对话框 -->
  530. <el-dialog
  531. v-model="batchDateDialogVisible"
  532. title="批量设置采购时间"
  533. width="400px"
  534. :close-on-click-modal="false"
  535. >
  536. <el-form label-width="100px">
  537. <el-form-item label="采购时间:">
  538. <el-date-picker
  539. v-model="batchDate"
  540. type="date"
  541. placeholder="请选择采购时间"
  542. format="YYYY-MM-DD"
  543. value-format="YYYY-MM-DD"
  544. style="width: 100%"
  545. />
  546. </el-form-item>
  547. </el-form>
  548. <template #footer>
  549. <span class="dialog-footer">
  550. <el-button type="primary" @click="confirmBatchSetDate">确定</el-button>
  551. <el-button @click="batchDateDialogVisible = false">取消</el-button>
  552. </span>
  553. </template>
  554. </el-dialog>
  555. <Drawer ref="drawerRef" :handleClose="callbackDrawer">
  556. <template #header="{ params }">
  557. <h4 :id="params.titleId" :class="params.titleClass">{{ isNew ? '添加' : '编辑' }} - 采购明细</h4>
  558. </template>
  559. <el-form ref="ruleFormRef" :model="form" :rules="rules">
  560. <el-form-item label="名称:" :label-width="formLabelWidth" prop="T_name">
  561. <el-input v-model="form.T_name" type="text" autocomplete="off" placeholder="请输入名称" />
  562. </el-form-item>
  563. <el-form-item label="位号:" :label-width="formLabelWidth" prop="T_bit_number">
  564. <el-input v-model="form.T_bit_number" type="text" autocomplete="off" placeholder="请输入位号" />
  565. </el-form-item>
  566. <el-form-item label="封装:" :label-width="formLabelWidth" prop="T_packaging">
  567. <el-input v-model="form.T_packaging" type="text" autocomplete="off" placeholder="请输入封装" />
  568. </el-form-item>
  569. <el-form-item label="型号:" :label-width="formLabelWidth" prop="T_model">
  570. <el-input v-model="form.T_model" type="text" autocomplete="off" placeholder="请输入型号" />
  571. </el-form-item>
  572. <el-form-item label="规格:" :label-width="formLabelWidth" prop="T_spec">
  573. <el-input v-model="form.T_spec" type="text" autocomplete="off" placeholder="请输入规格" />
  574. </el-form-item>
  575. <el-form-item label="数量:" :label-width="formLabelWidth" prop="T_quantity">
  576. <el-input-number
  577. v-model="form.T_quantity"
  578. :min="0"
  579. :precision="0"
  580. :controls="false"
  581. placeholder="请输入数量"
  582. style="width: 100%; text-align: left"
  583. @blur="form.T_quantity === 0 && (form.T_quantity = null)"
  584. @focus="form.T_quantity === null && (form.T_quantity = 0)"
  585. />
  586. </el-form-item>
  587. <el-form-item label="参考网址:" :label-width="formLabelWidth" prop="T_reference_site">
  588. <el-input v-model="form.T_reference_site" type="text" autocomplete="off" placeholder="请输入参考网址" />
  589. </el-form-item>
  590. <el-form-item label="需求:" :label-width="formLabelWidth" prop="T_demand">
  591. <el-input v-model="form.T_demand" type="text" autocomplete="off" placeholder="请输入需求" />
  592. </el-form-item>
  593. <el-form-item label="备注:" :label-width="formLabelWidth" prop="T_remark">
  594. <el-input v-model="form.T_remark" type="text" autocomplete="off" placeholder="请输入备注" />
  595. </el-form-item>
  596. <el-form-item v-if="isShow !== 'myPurchase'" label="状态:" :label-width="formLabelWidth" prop="T_state">
  597. <el-radio-group v-model="form.T_state">
  598. <el-radio :label="1">待采购</el-radio>
  599. <el-radio :label="2">已采购</el-radio>
  600. </el-radio-group>
  601. </el-form-item>
  602. <el-form-item v-if="isShow !== 'myPurchase'" label="采购时间:" :label-width="formLabelWidth" prop="T_date">
  603. <el-date-picker
  604. style="flex: 0 0 50%"
  605. class="my-date-picker"
  606. v-model="form.T_date"
  607. type="date"
  608. placeholder="采购时间"
  609. format="YYYY-MM-DD"
  610. value-format="YYYY-MM-DD"
  611. />
  612. </el-form-item>
  613. <el-form-item label="采购单价:" :label-width="formLabelWidth" prop="T_unit_price">
  614. <el-input-number
  615. v-model="form.T_unit_price"
  616. :min="0"
  617. :precision="2"
  618. :controls="false"
  619. placeholder="请输入采购单价"
  620. style="width: 100%; text-align: left"
  621. @blur="form.T_unit_price === 0 && (form.T_unit_price = null)"
  622. @focus="form.T_unit_price === null && (form.T_unit_price = 0)"
  623. />
  624. </el-form-item>
  625. <el-form-item label="采购金额:" :label-width="formLabelWidth" prop="T_amount">
  626. <el-input-number
  627. v-model="form.T_amount"
  628. :min="0"
  629. :precision="2"
  630. :controls="false"
  631. placeholder="请输入采购金额"
  632. style="width: 100%; text-align: left"
  633. @blur="form.T_amount === 0 && (form.T_amount = null)"
  634. @focus="form.T_amount === null && (form.T_amount = 0)"
  635. />
  636. </el-form-item>
  637. <el-form-item :label-width="formLabelWidth">
  638. <el-button v-if="isNew" class="btn" type="primary" @click="addPurchaseDetail(ruleFormRef)"
  639. >添加</el-button
  640. >
  641. <el-button v-else class="btn" type="primary" @click="addPurchaseDetail(ruleFormRef)"
  642. >修改</el-button
  643. >
  644. </el-form-item>
  645. </el-form>
  646. </Drawer>
  647. </template>
  648. <style scoped lang="scss">
  649. :deep(.el-drawer__body .el-table .cell) {
  650. white-space: normal !important;
  651. }
  652. .el-form-item {
  653. margin-bottom: 18px;
  654. }
  655. // 数字输入框样式优化
  656. :deep(.el-input-number) {
  657. .el-input__inner {
  658. text-align: left !important;
  659. }
  660. // 当值为0时隐藏显示
  661. &.is-empty .el-input__inner {
  662. color: transparent;
  663. }
  664. }
  665. // 表格中的数字输入框
  666. :deep(.el-table .el-input-number) {
  667. .el-input__inner {
  668. text-align: left !important;
  669. border: none;
  670. background: transparent;
  671. padding: 0 8px;
  672. }
  673. &:hover .el-input__inner {
  674. background: #f5f7fa;
  675. }
  676. &.is-focus .el-input__inner {
  677. background: #fff;
  678. border: 1px solid #409eff;
  679. }
  680. }
  681. </style>