ContractForm.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. <script setup lang="ts">
  2. import { ref, reactive, nextTick } from 'vue'
  3. import Drawer from '@/components/Drawer/index.vue'
  4. import type { FormInstance, FormRules } from 'element-plus'
  5. import { Delete } from '@element-plus/icons-vue'
  6. import { GlobalStore } from '@/stores/index'
  7. import Upload from '@/components/Upload/index.vue'
  8. import {
  9. Storehouse_Contract_Add,
  10. Storehouse_Contract_Edit,
  11. Storehouse_Contract_Product_List,
  12. Storehouse_Contract_Gen_Number
  13. } from '@/api/storehouse/index'
  14. import { ElMessage } from 'element-plus'
  15. import ImageCom from '@/components/Image/index.vue'
  16. import InStorageProduct from '@/views/storehouse/inventory/InStorageProduct.vue'
  17. import ContractUser from '@/views/storehouse/outStock/receiveUser.vue'
  18. const isProduct = ref(false)
  19. let selectProductData: any[] = []
  20. const isNew = ref(true)
  21. const globalStore = GlobalStore()
  22. const User_tokey = globalStore.GET_User_tokey
  23. const formLabelWidth = ref('120px')
  24. const ruleFormRef = ref<FormInstance>()
  25. const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
  26. const uploadRef = ref<InstanceType<typeof Upload> | null>(null)
  27. const receiveUserdialog = ref<InstanceType<typeof ContractUser> | null>(null)
  28. const validate_T_product = (rule: any, value: any, callback: any) => {
  29. if (value === '') {
  30. callback(new Error('请选择产品明细'))
  31. } else if (value.includes(undefined)) {
  32. callback(new Error('请填写产品数量'))
  33. } else {
  34. callback()
  35. }
  36. }
  37. const rules = reactive<FormRules>({
  38. T_number: [{ required: true, message: '请输入物联网卡号', trigger: 'blur' }],
  39. T_customer: [{ required: true, message: '请输入客户名称', trigger: 'blur' }],
  40. T_type: [{ required: true, message: '请选择合同类型', trigger: 'blur' }],
  41. T_product: [{ validator: validate_T_product, trigger: 'blur' }],
  42. T_money: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
  43. T_date: [{ required: true, message: '请选择业务日期', trigger: 'blur' }]
  44. })
  45. const callbackDrawer = (done: () => void) => {
  46. resetForm(ruleFormRef.value)
  47. isNew.value = true
  48. selectProductData = []
  49. drawerProductRef.value?.clearSelection()
  50. isProduct.value = false
  51. done()
  52. }
  53. const resetForm = (formEl: FormInstance | undefined) => {
  54. if (!formEl) return
  55. tableData.value = []
  56. formEl.resetFields()
  57. }
  58. // 父级方法
  59. const emit = defineEmits<{ (event: 'onTableList'): void }>()
  60. interface FormType {
  61. T_uuid: string
  62. T_number: string
  63. T_customer: string
  64. T_type: any
  65. T_product: any
  66. T_money: string
  67. T_date: string
  68. T_remark: string
  69. T_pdf: string
  70. T_submit: string
  71. }
  72. const form = reactive<FormType>({
  73. T_uuid: '',
  74. T_number: '',
  75. T_customer: '',
  76. T_type: '',
  77. T_product: '',
  78. T_money: '',
  79. T_date: '',
  80. T_remark: '',
  81. T_pdf: '',
  82. T_submit: ''
  83. })
  84. const openDrawer = (type: string, row?: any) => {
  85. isNew.value = type === 'new' ? true : false
  86. if (!isNew.value) {
  87. nextTick(() => {
  88. editDataEcho(row)
  89. })
  90. }
  91. drawerRef.value?.openDrawer()
  92. }
  93. // edit data echo
  94. const editDataEcho = async (row: any) => {
  95. form.T_pdf = row.T_pdf
  96. form.T_date = row.T_date
  97. form.T_type = row.T_type
  98. form.T_money = row.T_money
  99. form.T_remark = row.T_remark
  100. form.T_number = row.T_number
  101. form.T_customer = row.T_customer
  102. const res: any = await Storehouse_Contract_Product_List({
  103. User_tokey,
  104. T_number: row.T_number
  105. })
  106. if (res.Code === 200) {
  107. res.Data &&
  108. (tableData.value = res.Data.map((item: any) => {
  109. item.Id = item.T_product_id
  110. item.T_img = item.T_product_img
  111. item.T_name = item.T_product_name
  112. item.T_class_name = item.T_product_class_name
  113. item.T_model = item.T_product_model
  114. item.T_spec = item.T_product_spec
  115. item.T_relation_sn = item.T_product_relation_sn
  116. item.count = item.T_product_total
  117. return item
  118. }))
  119. selectProductData = tableData.value
  120. blurHandle()
  121. }
  122. }
  123. const blurHandle = () => {
  124. form.T_product = tableData.value.map(item => {
  125. if (!item.count) return undefined
  126. return `${item.Id},${item.count}|`
  127. })
  128. }
  129. const deleteProduct = (row: any) => {
  130. tableData.value = tableData.value.filter(item => item.Id !== row.Id)
  131. // 设置产品的选中
  132. drawerProductRef.value?.selectTableChange(row)
  133. }
  134. const AddContract = (formEl: FormInstance | undefined) => {
  135. if (!formEl) return
  136. formEl.validate(async valid => {
  137. if (valid) {
  138. let res: any = {}
  139. let product = ''
  140. tableData.value.forEach(item => {
  141. product += `${item.Id},${item.count}|`
  142. })
  143. const params = {
  144. ...form,
  145. User_tokey,
  146. T_submit: form.T_uuid,
  147. T_product: product
  148. }
  149. if (isNew.value) {
  150. res = await Storehouse_Contract_Add(params)
  151. } else {
  152. res = await Storehouse_Contract_Edit(params)
  153. }
  154. if (res.Code === 200) {
  155. ElMessage.success(`${isNew.value ? '添加' : '修改'}合同成功!!`)
  156. nextTick(() => {
  157. drawerRef.value?.closeDrawer()
  158. emit('onTableList')
  159. resetForm(ruleFormRef.value)
  160. isNew.value = true
  161. })
  162. }
  163. } else {
  164. return false
  165. }
  166. })
  167. }
  168. const tableData = ref<any[]>([])
  169. const columns = [
  170. { type: 'index', label: '序号', width: 80, align: 'center ' },
  171. { label: '产品图片', prop: 'T_img', align: 'center ', name: 'T_img' },
  172. { label: '产品名称', prop: 'T_name', align: 'center ' },
  173. { label: '产品分类', prop: 'T_class_name', align: 'center ' },
  174. { label: '产品型号', prop: 'T_model', align: 'center ' },
  175. { label: '产品规格', prop: 'T_spec', align: 'center ' },
  176. { label: '是否关联SN', prop: 'T_relation_sn', align: 'center ', width: 120, name: 'T_relation_sn' },
  177. { label: '*数量', prop: 'count', align: 'center ', name: 'count' },
  178. { prop: 'operation', label: '操作', width: 80, fixed: 'right' }
  179. ]
  180. const drawerProductRef = ref<InstanceType<typeof InStorageProduct> | null>(null)
  181. /**
  182. * 添加产品
  183. */
  184. const AddProductionDetailed = () => {
  185. isProduct.value = true
  186. nextTick(() => {
  187. drawerProductRef.value?.openDrawer()
  188. })
  189. }
  190. /**
  191. * 产品选择 是否
  192. */
  193. const ProductselectionChange = (row: any) => {
  194. const index = tableData.value.findIndex((item: any) => item.Id === row.Id)
  195. if (index === -1) {
  196. row.count = ''
  197. tableData.value.push(row)
  198. } else {
  199. tableData.value.splice(index, 1)
  200. }
  201. }
  202. /**
  203. * 全选
  204. */
  205. const ProductSelectionAllChange = (selection: any[]) => (tableData.value = selection)
  206. const getContractNumber = async () => {
  207. const res: any = await Storehouse_Contract_Gen_Number({ User_tokey })
  208. if (res.Code === 200) form.T_number = res.Data
  209. }
  210. /**
  211. * 合同负责人
  212. */
  213. const selectApprover = () => receiveUserdialog.value?.openDrawer()
  214. const getReceiveInfo = ({ T_uuid, T_name }: { T_uuid: string; T_name: string }) => {
  215. form.T_submit = T_name
  216. form.T_uuid = T_uuid
  217. }
  218. defineExpose({
  219. openDrawer
  220. })
  221. </script>
  222. <template>
  223. <div class="contract-form">
  224. <Drawer ref="drawerRef" :handleClose="callbackDrawer" size="80%">
  225. <template #header="{ params }">
  226. <h4 :id="params.titleId" :class="params.titleClass">{{ isNew ? '添加' : '编辑' }} - 合同</h4>
  227. </template>
  228. <el-form ref="ruleFormRef" :model="form" :rules="rules">
  229. <el-divider border-style="dashed" />
  230. <el-form-item label="合同编号:" :label-width="formLabelWidth" prop="T_number">
  231. <div>
  232. <el-input v-model="form.T_number" :disabled="!isNew" placeholder="请输入合同编号" class="w-50" />
  233. <el-button type="primary" @click="getContractNumber">生成合同编号</el-button>
  234. </div>
  235. </el-form-item>
  236. <el-form-item label="客户名称:" :label-width="formLabelWidth" prop="T_customer">
  237. <el-input v-model="form.T_customer" placeholder="请输入客户名称" class="w-50" />
  238. </el-form-item>
  239. <el-form-item label="产品明细:" :label-width="formLabelWidth" prop="T_product">
  240. <el-table
  241. border
  242. stripe
  243. :data="tableData"
  244. style="width: 100%"
  245. :header-cell-style="{ background: '#dedfe0', height: '50px' }"
  246. >
  247. <template v-for="item in columns" :key="item.prop">
  248. <el-table-column v-bind="item" v-if="item.fixed !== 'right'">
  249. <template #header v-if="item.prop === 'count'">
  250. <span style="color: red">*数量</span>
  251. </template>
  252. <template #default="{ row }" v-if="item.prop === item.name">
  253. <el-input
  254. v-if="item.prop === 'count'"
  255. v-model.number="row.count"
  256. type="text"
  257. autocomplete="off"
  258. @blur="blurHandle"
  259. />
  260. <span v-if="item.prop === 'T_relation_sn'">
  261. <el-tag v-if="row.T_relation_sn === 1" effect="dark">是</el-tag>
  262. <el-tag v-else type="success" effect="dark">否</el-tag>
  263. </span>
  264. <ImageCom v-if="item.prop === 'T_img'" :src="row.T_img" />
  265. </template>
  266. </el-table-column>
  267. <el-table-column v-bind="item" v-if="item.fixed === 'right'">
  268. <template #default="{ row }">
  269. <el-button link type="danger" size="small" :icon="Delete" @click="deleteProduct(row)">删除</el-button>
  270. </template>
  271. </el-table-column>
  272. </template>
  273. <template #append>
  274. <el-button type="primary" @click="AddProductionDetailed">
  275. <el-icon><Plus /></el-icon><span style="margin-left: 6px">添加产品</span>
  276. </el-button>
  277. </template>
  278. </el-table>
  279. </el-form-item>
  280. <el-form-item label="签订时间:" :label-width="formLabelWidth" prop="T_date">
  281. <el-date-picker
  282. class="my-date-picker"
  283. style="width: 21.5rem"
  284. v-model="form.T_date"
  285. type="date"
  286. placeholder="签订时间"
  287. format="YYYY-MM-DD"
  288. value-format="YYYY-MM-DD"
  289. />
  290. </el-form-item>
  291. <el-form-item label="合同金额:" :label-width="formLabelWidth" prop="T_money">
  292. <el-input v-model="form.T_money" type="text" autocomplete="off" placeholder="请输入合同金额" class="w-50" />
  293. </el-form-item>
  294. <el-form-item label="合同负责人:" :label-width="formLabelWidth" prop="T_submit">
  295. <el-input v-model="form.T_submit" placeholder="请选择合同负责人" class="w-50" @focus="selectApprover" />
  296. </el-form-item>
  297. <el-form-item label="合同备注:" :label-width="formLabelWidth" prop="T_remark">
  298. <el-input
  299. class="w-50"
  300. v-model="form.T_remark"
  301. :autosize="{ minRows: 4, maxRows: 6 }"
  302. type="textarea"
  303. placeholder="请输入备注信息"
  304. />
  305. </el-form-item>
  306. <el-form-item label="上传附件:" :label-width="formLabelWidth" prop="T_pdf">
  307. <Upload
  308. v-model="form.T_pdf"
  309. class="w-50"
  310. ref="uploadRef"
  311. :limit="1"
  312. successText="文件上传成功!!"
  313. errorText="文件上传失败"
  314. accept=".pdf"
  315. listType="text"
  316. >
  317. <el-button type="primary">上传文件</el-button>
  318. <template #tip> 只能上传pdf格式文件!!</template>
  319. </Upload>
  320. </el-form-item>
  321. <div class="btn">
  322. <el-divider>
  323. <el-button>取消</el-button>
  324. <el-button v-if="isNew" color="#626aef" @click="AddContract(ruleFormRef)">提交</el-button>
  325. <el-button v-else color="#626aef" @click="AddContract(ruleFormRef)">修改</el-button>
  326. </el-divider>
  327. </div>
  328. </el-form>
  329. </Drawer>
  330. <ContractUser ref="receiveUserdialog" @onUserInfo="getReceiveInfo" title="合同负责人" />
  331. <InStorageProduct
  332. v-if="isProduct"
  333. ref="drawerProductRef"
  334. :selectProductData="selectProductData"
  335. @ontableData="ProductselectionChange"
  336. @ontableDataAll="ProductSelectionAllChange"
  337. ></InStorageProduct>
  338. </div>
  339. </template>
  340. <style scoped lang="scss">
  341. .contract-form {
  342. :deep(.el-table--border .el-table__cell) {
  343. border-right: 0;
  344. }
  345. :deep(.table-header),
  346. :deep(.card) {
  347. border: 0;
  348. }
  349. .box-card {
  350. height: 100%;
  351. :deep(.el-card__body) {
  352. height: calc(100% - 70px);
  353. }
  354. }
  355. .btn {
  356. margin-top: 32px;
  357. display: flex;
  358. justify-content: center;
  359. .el-button {
  360. padding: 0 32px;
  361. }
  362. }
  363. .w-50 {
  364. width: 21.5rem;
  365. }
  366. }
  367. </style>