PurchaseForm.vue 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  1. <template>
  2. <view>
  3. <cu-custom :backUrl="'/pages/index/index'" :isBack="true" bgColor="bg-gradual-blue">
  4. <block slot="content">采购申请</block>
  5. </cu-custom>
  6. <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules"
  7. ref="inputForm" v-if="!nodeFlag">
  8. <u-form-item label="采购编号" borderBottom prop="purchaseNo">
  9. <u--input placeholder='自动生成' v-model="inputForm.purchaseNo" disabled></u--input>
  10. </u-form-item>
  11. <u-form-item label="采购名称" borderBottom prop="purchaseSketch" :required="true">
  12. <u--input placeholder='请填写采购名称' v-model="inputForm.purchaseSketch"></u--input>
  13. </u-form-item>
  14. <u-form-item label="经办人" borderBottom prop="handledBy">
  15. <u--input placeholder='' v-model="inputForm.handledBy" disabled></u--input>
  16. </u-form-item>
  17. <u-form-item label="经办人部门" borderBottom prop="handledByOfficeName">
  18. <u--input placeholder='' v-model="inputForm.handledByOfficeName" disabled></u--input>
  19. </u-form-item>
  20. <u-form-item label="采购申请时间" borderBottom prop="purchaseDate" :required="true">
  21. <el-date-picker v-model="inputForm.purchaseDate" type="date" placeholder="请选择采购申请时间" style="width:100%"
  22. size="default" placement="bottom-start" clearable>
  23. </el-date-picker>
  24. </u-form-item>
  25. <u-form-item label="采购方式" borderBottom prop="purchaseMode" :required="true">
  26. <jp-picker placeholder='请选择采购方式' v-model="inputForm.purchaseMode" rangeKey="label" rangeValue="value"
  27. :range="[
  28. { label: '办公室采购', value: '1' },
  29. { label: '自行采购', value: '2' },
  30. ]"></jp-picker>
  31. </u-form-item>
  32. <u-form-item label="备注" borderBottom prop="remarks">
  33. <u--textarea placeholder='请填写备注信息' :rows="5" :maxlength="500" v-model="inputForm.remarks"></u--textarea>
  34. </u-form-item>
  35. <el-row :gutter="15" :key="index_experience" v-for="(item, index_experience) in this.inputForm.detailInfos">
  36. <el-col :span="24">
  37. <u-form-item label="">
  38. <el-divider content-position="left"> 采购详情 {{ index_experience + 1 }}</el-divider>
  39. </u-form-item>
  40. </el-col>
  41. <el-col :span="24">
  42. <u-form-item label="采购人" :prop="'detailInfos[' + index_experience + '].purchaserAgent'"
  43. :required="true" :rules="[
  44. ]">
  45. <u--input v-model="inputForm.detailInfos[index_experience].purchaserAgent" placeholder="请选择采购人"
  46. @focus="openUserPullForm(index_experience)" clearable></u--input>
  47. </u-form-item>
  48. <u-form-item label="采购人部门" :prop="'detailInfos[' + index_experience + '].procurementOffice'"
  49. :required="true" :rules="[
  50. ]">
  51. <u--input v-model="inputForm.detailInfos[index_experience].procurementOffice" placeholder=""
  52. clearable></u--input>
  53. </u-form-item>
  54. <u-form-item label="采购类型" :prop="'detailInfos[' + index_experience + '].procurementType'"
  55. :required="true" :rules="[
  56. ]">
  57. <u--input v-model="inputForm.detailInfos[index_experience].procurementType"
  58. placeholder="请选择采购类型" @focus="showPicker(index_experience)" clearable></u--input>
  59. </u-form-item>
  60. <my-dropdown :index_experience="index_experience" :inputForm="inputForm"></my-dropdown>
  61. <!--<u-form-item label="商品名称" :prop="'detailInfos[' + index_experience + '].tradeName'"
  62. :rules="[
  63. ]">
  64. <u--input v-model="inputForm.detailInfos[index_experience].tradeName" placeholder="请选择物品名称" clearable></u--input>
  65. </u-form-item>-->
  66. <supplier-selector :index_experience="index_experience" :inputForm="inputForm"></supplier-selector>
  67. <!-- <u-form-item label="供应商" :prop="'detailInfos[' + index_experience + '].supplierName'" -->
  68. <!-- :rules="[-->
  69. <!-- ]">-->
  70. <!-- <u--input v-model="inputForm.detailInfos[index_experience].supplierName" placeholder="请选择供应商" @focus="showGoods(index_experience)" clearable></u--input>-->
  71. <!-- </u-form-item>-->
  72. <u-form-item label="商品单价(元)" :prop="'detailInfos[' + index_experience + '].tradePrice'" :rules="[
  73. ]">
  74. <u--input @blur="onInputCode(index_experience, $event, 'tradePrice')"
  75. v-model="inputForm.detailInfos[index_experience].tradePrice" placeholder="请输入商品单价(元)"
  76. clearable></u--input>
  77. </u-form-item>
  78. <u-form-item label="商品数量" :prop="'detailInfos[' + index_experience + '].tradeNumber'" :rules="[
  79. ]">
  80. <u--input @blur="onInputCode(index_experience, $event, 'tradeNumber')"
  81. v-model="inputForm.detailInfos[index_experience].tradeNumber" placeholder="请输入商品数量"
  82. clearable></u--input>
  83. </u-form-item>
  84. <u-form-item label="商品总价" :prop="'detailInfos[' + index_experience + '].priceSum'" :rules="[
  85. ]">
  86. <u--input v-model="inputForm.detailInfos[index_experience].priceSum" placeholder="请输入商品总价"
  87. :readonly="true" clearable></u--input>
  88. </u-form-item>
  89. <u-form-item label="单位" :prop="'detailInfos[' + index_experience + '].company'" :rules="[
  90. ]">
  91. <u--input v-model="inputForm.detailInfos[index_experience].company" placeholder="请输入单位"
  92. clearable></u--input>
  93. </u-form-item>
  94. <u-form-item label="备注" :prop="'detailInfos[' + index_experience + '].remarks'" :rules="[
  95. ]">
  96. <u--input v-model="inputForm.detailInfos[index_experience].remarks" placeholder="请输入备注"
  97. clearable></u--input>
  98. </u-form-item>
  99. <u-form-item label="文件上传">
  100. <!-- <el-upload class="upload-demo"
  101. :action="`http://cpaoa.xgccpm.com/api/public-modules-server/oss/file/webUpload/upload`"
  102. :on-remove="(file, fileList) => handleRemove(file, fileList, index_experience, 'detail')"
  103. :file-list="inputForm.detailInfos[index_experience].fileInfoLost"
  104. :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList, index_experience, 'detail')"
  105. :limit="3">
  106. <el-button size="small" type="primary">点击上传</el-button>
  107. <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
  108. <template slot="file" slot-scope="{ file }"
  109. v-if="shouldShowFile(file, index_experience, 'detail') || testFlag">
  110. <span @click="handleFileClick(file)">{{ file.name }}</span>
  111. <el-button type="text" icon="el-icon-close"
  112. @click="handleDelete(file, index_experience, 'detail')">✕</el-button>
  113. </template>
  114. </el-upload> -->
  115. <UploadComponent :uploadUrl="`${uploadUrl}/public-modules-server/oss/file/webUpload/upload`"
  116. @onRemove="(file, fileList, fileIndex) => handleRemove(file, fileList, index_experience, fileIndex, 'detail')"
  117. @onSuccess="(file, fileList) => handleUploadSuccess(file, fileList, index_experience, 'detail')"
  118. :fileList="inputForm.detailInfos[index_experience].fileInfoLost" :limit="3"
  119. :isDelete="nodeFlag" :isUpload="nodeFlag">
  120. </UploadComponent>
  121. </u-form-item>
  122. </el-col>
  123. <el-col :span="24" style="text-align: center">
  124. <u-form-item label="">
  125. <el-button style="width: 100%" type="danger" @click="removeRow(index_experience)" plain>删除采购详情
  126. {{ index_experience + 1 }}</el-button>
  127. </u-form-item>
  128. </el-col>
  129. </el-row>
  130. <u-form-item label="">
  131. <el-button style="width: 100%" type="primary" @click="addRow()" plain>新增采购详情</el-button>
  132. </u-form-item>
  133. <u-form-item label="附件">
  134. <!-- <el-upload class="upload-demo"
  135. :action="`http://cpaoa.xgccpm.com/api/public-modules-server/oss/file/webUpload/upload`"
  136. :on-remove="(file, fileList) => handleRemove(file, fileList, '', '')" :file-list="inputForm.files"
  137. :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList, '', '')"
  138. :limit="3">
  139. <el-button size="small" type="primary">点击上传</el-button>
  140. <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
  141. <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file) || testFlag">
  142. <span @click="handleFileClick(file)">{{ file.name }}</span>
  143. <el-button type="text" icon="el-icon-close" @click="handleDelete(file)">✕</el-button>
  144. </template>
  145. </el-upload> -->
  146. <UploadComponent :uploadUrl="`${uploadUrl}/public-modules-server/oss/file/webUpload/upload`"
  147. @onRemove="(file, fileList, fileIndex) => handleRemove(file, fileList, fileIndex, '')"
  148. @onSuccess="(file, fileList) => handleUploadSuccess(file, fileList, '', '')"
  149. :fileList="inputForm.files" :limit="3" :isDelete="nodeFlag" :isUpload="nodeFlag">
  150. </UploadComponent>
  151. </u-form-item>
  152. </u--form>
  153. <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules"
  154. ref="inputForm" v-else-if="nodeFlag">
  155. <u-form-item label="采购编号" borderBottom prop="purchaseNo">
  156. <u--input placeholder='自动生成' v-model="inputForm.purchaseNo" disabled></u--input>
  157. </u-form-item>
  158. <u-form-item label="采购名称" borderBottom prop="purchaseSketch" :required="true">
  159. <u--input placeholder='请填写采购名称' disabled v-model="inputForm.purchaseSketch"></u--input>
  160. </u-form-item>
  161. <u-form-item label="经办人" borderBottom prop="handledBy">
  162. <u--input placeholder='' v-model="inputForm.handledBy" disabled></u--input>
  163. </u-form-item>
  164. <u-form-item label="经办人部门" borderBottom prop="handledByOfficeName">
  165. <u--input placeholder='' v-model="inputForm.handledByOfficeName" disabled></u--input>
  166. </u-form-item>
  167. <u-form-item label="采购申请时间" borderBottom prop="purchaseDate" :required="true">
  168. <el-date-picker :disabled="true" v-model="inputForm.purchaseDate" type="date" placeholder="请选择采购申请时间"
  169. style="width:100%" size="default" placement="bottom-start" clearable>
  170. </el-date-picker>
  171. </u-form-item>
  172. <u-form-item label="采购方式" borderBottom prop="purchaseMode" :required="true">
  173. <jp-picker placeholder='请选择采购方式' v-model="inputForm.purchaseMode" :disabled="true" rangeKey="label"
  174. rangeValue="value" :range="[
  175. { label: '办公室采购', value: '1' },
  176. { label: '自行采购', value: '2' },
  177. ]"></jp-picker>
  178. </u-form-item>
  179. <u-form-item label="备注" borderBottom prop="remarks">
  180. <u--textarea placeholder='请填写备注信息' :disabled="true" :rows="5" :maxlength="500"
  181. v-model="inputForm.remarks"></u--textarea>
  182. </u-form-item>
  183. <el-row :gutter="15" :key="index_experience" v-for="(item, index_experience) in this.inputForm.detailInfos">
  184. <el-col :span="24">
  185. <u-form-item label="">
  186. <el-divider content-position="left"> 采购详情 {{ index_experience + 1 }}</el-divider>
  187. </u-form-item>
  188. </el-col>
  189. <el-col :span="24">
  190. <u-form-item label="采购人" :prop="'detailInfos[' + index_experience + '].purchaserAgent'"
  191. :required="true" :rules="[
  192. ]">
  193. <el-input v-model="inputForm.detailInfos[index_experience].purchaserAgent" :disabled="true"
  194. placeholder="请选择采购人" @focus="openUserPullForm(index_experience)" clearable></el-input>
  195. </u-form-item>
  196. <u-form-item label="采购人部门" :prop="'detailInfos[' + index_experience + '].procurementOffice'"
  197. :required="true" :rules="[
  198. ]">
  199. <el-input v-model="inputForm.detailInfos[index_experience].procurementOffice" :disabled="true"
  200. placeholder="" clearable></el-input>
  201. </u-form-item>
  202. <u-form-item label="采购类型" :prop="'detailInfos[' + index_experience + '].procurementType'"
  203. :required="true" :rules="[
  204. ]">
  205. <el-input v-model="inputForm.detailInfos[index_experience].procurementType" :disabled="true"
  206. placeholder="请选择采购类型" @focus="showPicker(index_experience)" clearable></el-input>
  207. </u-form-item>
  208. <my-dropdown :index_experience="index_experience" :disabled="true"
  209. :inputForm="inputForm"></my-dropdown>
  210. <!-- <u-form-item label="商品名称" :prop="'detailInfos[' + index_experience + '].tradeName'" -->
  211. <!-- :rules="[-->
  212. <!-- ]">-->
  213. <!-- <el-input v-model="inputForm.detailInfos[index_experience].tradeName" placeholder="请选择物品名称" @focus="showGoods(index_experience)" clearable></el-input>-->
  214. <!-- </u-form-item>-->
  215. <supplier-selector :index_experience="index_experience" :disabled="true"
  216. :inputForm="inputForm"></supplier-selector>
  217. <!-- <u-form-item label="供应商" :prop="'detailInfos[' + index_experience + '].supplierName'" -->
  218. <!-- :rules="[-->
  219. <!-- ]">-->
  220. <!-- <el-input v-model="inputForm.detailInfos[index_experience].supplierName" placeholder="请选择供应商" @focus="showGoods(index_experience)" clearable></el-input>-->
  221. <!-- </u-form-item>-->
  222. <u-form-item label="商品单价(元)" :prop="'detailInfos[' + index_experience + '].tradePrice'" :rules="[
  223. ]">
  224. <el-input @change="changeValue" :disabled="true"
  225. v-model="inputForm.detailInfos[index_experience].tradePrice" placeholder="请输入商品单价(元)"
  226. clearable></el-input>
  227. </u-form-item>
  228. <u-form-item label="商品数量" :prop="'detailInfos[' + index_experience + '].tradeNumber'" :rules="[
  229. ]">
  230. <el-input @change="changeValue" v-model="inputForm.detailInfos[index_experience].tradeNumber"
  231. :disabled="true" placeholder="请输入商品数量" clearable></el-input>
  232. </u-form-item>
  233. <u-form-item label="商品总价" :prop="'detailInfos[' + index_experience + '].priceSum'" :rules="[
  234. ]">
  235. <el-input v-model="inputForm.detailInfos[index_experience].priceSum" :disabled="true"
  236. placeholder="请输入商品总价" clearable></el-input>
  237. </u-form-item>
  238. <u-form-item label="单位" :prop="'detailInfos[' + index_experience + '].company'" :rules="[
  239. ]">
  240. <el-input v-model="inputForm.detailInfos[index_experience].company" :disabled="true"
  241. placeholder="请输入单位" clearable></el-input>
  242. </u-form-item>
  243. <u-form-item label="备注" :prop="'detailInfos[' + index_experience + '].remarks'" :rules="[
  244. ]">
  245. <el-input v-model="inputForm.detailInfos[index_experience].remarks" :disabled="true"
  246. placeholder="请输入备注" clearable></el-input>
  247. </u-form-item>
  248. <u-form-item label="文件上传">
  249. <!-- <el-upload :disabled="true" class="upload-demo"
  250. :action="`http://cpaoa.xgccpm.com/api/public-modules-server/oss/file/webUpload/upload`"
  251. :on-remove="(file, fileList) => handleRemove(file, fileList, index_experience, 'detail')"
  252. :file-list="inputForm.detailInfos[index_experience].fileInfoLost"
  253. :on-success="(response, file, fileList) => handleUploadSuccess( file, fileList, index_experience, 'detail')"
  254. :limit="3">
  255. <el-button size="small" :disabled="true" type="primary">点击上传</el-button>
  256. <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
  257. <template slot="file" slot-scope="{ file }"
  258. v-if="shouldShowFile(file, index_experience, 'detail') || testFlag">
  259. <span @click="handleFileClick(file)">{{ file.name }}</span>
  260. <el-button type="text" icon="el-icon-close"
  261. @click="handleDelete(file, index_experience, 'detail')">✕</el-button>
  262. </template>
  263. </el-upload> -->
  264. <UploadComponent :uploadUrl="`${uploadUrl}/public-modules-server/oss/file/webUpload/upload`"
  265. @onRemove="(file, fileList, fileIndex) => handleRemove(file, fileList, index_experience, fileIndex, 'detail')"
  266. @onSuccess="(file, fileList) => handleUploadSuccess(file, fileList, index_experience, 'detail')"
  267. :fileList="inputForm.detailInfos[index_experience].fileInfoLost" :limit="3"
  268. :isDelete="nodeFlag" :isUpload="nodeFlag">
  269. </UploadComponent>
  270. </u-form-item>
  271. </el-col>
  272. <el-col :span="24" style="text-align: center">
  273. <u-form-item label="">
  274. <el-button style="width: 100%" :disabled="true" type="danger"
  275. @click="removeRow(index_experience)" plain>删除采购详情 {{ index_experience + 1 }}</el-button>
  276. </u-form-item>
  277. </el-col>
  278. </el-row>
  279. <u-form-item label="">
  280. <el-button style="width: 100%" type="primary" :disabled="true" @click="addRow()"
  281. plain>新增采购详情</el-button>
  282. </u-form-item>
  283. <u-form-item label="附件">
  284. <!-- <el-upload :disabled="true" class="upload-demo"
  285. :action="`http://cpaoa.xgccpm.com/api/public-modules-server/oss/file/webUpload/upload`"
  286. :on-remove="(file, fileList) => handleRemove(file, fileList, '', '')" :file-list="inputForm.files"
  287. :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList, '', '')"
  288. :limit="3">
  289. <el-button size="small" :disabled="true" type="primary">点击上传</el-button>
  290. <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
  291. <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file) || testFlag">
  292. <span @click="handleFileClick(file)">{{ file.name }}</span>
  293. <el-button type="text" icon="el-icon-close" @click="handleDelete(file)">✕</el-button>
  294. </template>
  295. </el-upload> -->
  296. <UploadComponent :uploadUrl="`${uploadUrl}/public-modules-server/oss/file/webUpload/upload`"
  297. @onRemove="(file, fileList, fileIndex) => handleRemove(file, fileList, '', fileIndex, '')"
  298. @onSuccess="(file, fileList) => handleUploadSuccess(file, fileList, '', '')"
  299. :fileList="inputForm.files" :limit="3" :isDelete="nodeFlag" :isUpload="nodeFlag">
  300. </UploadComponent>
  301. </u-form-item>
  302. </u--form>
  303. <user-select ref="userPicker" @input="handleEvent"></user-select>
  304. <ba-tree-picker ref="treePicker" :multiple='false' @select-change="selectChange" title="类型选择"
  305. :localdata="listData" valueKey="value" textKey="label" childrenKey="children" />
  306. <goods-info-picker ref="goodsPicker" :multiple='false' @select-goods-change="selectGoodsChange" title="物品名称"
  307. :localdata="goodsListData" valueKey="value" textKey="label" childrenKey="children" />
  308. </view>
  309. </template>
  310. <script>
  311. import userSelect from '@/components/user-select/user-select-radio.vue'
  312. import OSSService from "@/api/sys/OSSService"
  313. import SupplierSelector from './SupplierSelector';
  314. import MyDropdown from './MyDropdown';
  315. import goodsInfoPicker from '../collect/GoodsInfoPicker'
  316. import MaterialTypeService from '@/api/materialManagement/MaterialTypeService'
  317. import WareHouseService from '@/api/materialManagement/WareHouseService'
  318. import materialManagementService from '@/api/materialManagement/MaterialManagementService'
  319. import CommonApi from '@/api/common/CommonApi'
  320. import baTreePicker from "@/components/ba-tree-picker/ba-tree-picker.vue"
  321. import { mapState, mapMutations, mapActions } from 'vuex'
  322. import registerService from '@/api/human/register/RegisterService'
  323. import UploadComponent from '@/pages/common/UploadComponent.vue';
  324. import upload from '@/utils/upload.js'
  325. export default {
  326. components: {
  327. userSelect,
  328. baTreePicker,
  329. goodsInfoPicker,
  330. 'my-dropdown': MyDropdown,
  331. 'supplier-selector': SupplierSelector,
  332. UploadComponent
  333. },
  334. computed: mapState({
  335. userInfo: (state) => state.user.userInfo,
  336. avatar: (state) => state.user.avatar
  337. }),
  338. data() {
  339. return {
  340. uploadUrl: upload.UPLOAD_URL,
  341. showFileList: [], // 控制每个文件是否显示的数组
  342. showFileList2: [], // 控制每个文件是否显示的数组
  343. testFlag: false,
  344. nodeFlag: false,
  345. loading: false,
  346. listData: [],
  347. fileList3: [],
  348. goodsListData: [],
  349. materialList: [],
  350. searchForm: {
  351. wareHouseType: '',
  352. },
  353. inputForm: {
  354. purchaseNo: '',
  355. purchaseSketch: '',
  356. handledBy: '',
  357. handledById: '',
  358. handledByOffice: '',
  359. handledByOfficeName: '',
  360. purchaseDate: '',
  361. purchaseMode: '',
  362. remarks: '',
  363. detailInfos: [],
  364. files: [], // 附件信息
  365. procInsId: ''
  366. },
  367. rules: {
  368. 'purchaseDate': [
  369. {
  370. required: true,
  371. message: '采购申请时间不能为空',
  372. trigger: ['blur', 'change']
  373. }
  374. ],
  375. 'purchaseSketch': [
  376. {
  377. required: true,
  378. message: '采购名称不能为空',
  379. trigger: ['blur', 'change']
  380. }
  381. ],
  382. 'purchaseMode': [
  383. {
  384. required: true,
  385. message: '采购方式不能为空',
  386. trigger: ['blur', 'change']
  387. }
  388. ],
  389. }
  390. }
  391. },
  392. materialTypeService: null,
  393. ossService: null,
  394. wareHouseService: null,
  395. commonApi: null,
  396. // 页面加载时执行
  397. created() {
  398. this.commonApi = new CommonApi()
  399. this.materialTypeService = new MaterialTypeService()
  400. this.ossService = new OSSService()
  401. this.wareHouseService = new WareHouseService()
  402. this.materialTypeService.cgList().then((data) => {
  403. this.materialList = data
  404. }).catch((e) => {
  405. throw e
  406. })
  407. this.inputForm.handledBy = this.userInfo.name
  408. this.inputForm.handledById = this.userInfo.id
  409. this.inputForm.handledByOffice = this.userInfo.officeDTO.id
  410. this.inputForm.handledByOfficeName = this.userInfo.officeDTO.name
  411. // 监听事件
  412. uni.$on('eventName', (data) => {
  413. // 在这里处理传递过来的数据
  414. //循环遍历采购详情,估计index将用户id与用户名称放入到采购人里面
  415. this.inputForm.detailInfos.forEach((detail, index) => {
  416. if (index === parseInt(data.index)) {
  417. detail.purchaserAgent = data.name
  418. detail.purchaserAgentId = data.id
  419. detail.procurementOffice = data.officeDTO.name
  420. }
  421. })
  422. });
  423. },
  424. props: {
  425. businessId: {
  426. type: String,
  427. default: ''
  428. },
  429. formReadOnly: {
  430. type: Boolean,
  431. default: false
  432. },
  433. status: {
  434. type: String,
  435. default: ''
  436. }
  437. },
  438. watch: {
  439. 'businessId': {
  440. handler(newVal) {
  441. if (this.businessId) {
  442. this.init(this.businessId)
  443. } else {
  444. this.$nextTick(() => {
  445. // this.$refs.inputForm.reset()
  446. })
  447. }
  448. },
  449. immediate: true,
  450. deep: false
  451. }
  452. },
  453. methods: {
  454. // 显示选择器
  455. showPicker(index) {
  456. this.$refs.treePicker._show(index);
  457. },
  458. showGoods(index) {
  459. this.searchForm.wareHouseType = this.inputForm.detailInfos[index].procurementTypeId
  460. this.wareHouseService.wareHouseSummaryList({
  461. 'current': 0,
  462. 'size': -1,
  463. 'orders': [],
  464. ...this.searchForm
  465. }).then((data) => {
  466. this.goodsListData = data.records
  467. })
  468. this.$refs.goodsPicker._show(index);
  469. },
  470. //监听选择
  471. selectChange(ids, names, index) {
  472. // this.inputForm.detailInfos.forEach((detail,inde) => {
  473. // if (inde === parseInt(index)) {
  474. // detail.collectType = names
  475. // detail.collectTypeId = ids[0]
  476. // }
  477. // })
  478. this.$set(this.inputForm.detailInfos, index, {
  479. ...this.inputForm.detailInfos[index],
  480. procurementType: names,
  481. procurementTypeId: ids[0]
  482. });
  483. },
  484. //监听选择
  485. selectGoodsChange(ids, names, index, tradeNumber) {
  486. // this.inputForm.detailInfos.forEach((detail,inde) => {
  487. // if (inde === parseInt(index)) {
  488. // detail.goodsName = names
  489. // detail.tradeNumber = tradeNumber
  490. // }
  491. // })
  492. this.$set(this.inputForm.detailInfos, index, {
  493. ...this.inputForm.detailInfos[index],
  494. tradeName: names,
  495. surplusNumber: tradeNumber
  496. });
  497. },
  498. init(id) {
  499. this.nodeFlag = true
  500. this.inputForm.id = id
  501. if (id) {
  502. materialManagementService.findById(id).then((data) => {
  503. // 只有从我发起的还有已办事项抄送给我 进入流程页面的时候才会有这个值
  504. if (this.status === 'testSee') {
  505. this.nodeFlag = true
  506. } else {
  507. this.commonApi.getTaskNameByProcInsId(data.procInsId).then((data) => {
  508. if (this.isNotEmpty(data)) {
  509. if (data === '重新发起申请' || this.isEmpty(data)) {
  510. this.nodeFlag = false
  511. } else {
  512. this.nodeFlag = true
  513. }
  514. }
  515. })
  516. }
  517. this.inputForm = this.recover(this.inputForm, data)
  518. this.inputForm.purchaseDate = new Date(data.purchaseDate);
  519. if (this.inputForm.files) {
  520. this.inputForm.files.forEach((item, index) => {
  521. this.$set(this.showFileList, index, true);
  522. })
  523. }
  524. this.inputForm.detailInfos.forEach((item, index) => {
  525. if (this.isNotEmpty(item.fileInfoLost)) {
  526. this.fileList3[index] = []
  527. item.fileInfoLost.forEach((item, index2) => {
  528. this.fileList3[index].push(item)
  529. this.$set(this.showFileList2, index2, true);
  530. })
  531. }
  532. this.inputForm.detailInfos[index].priceSum = parseFloat(parseFloat(this.inputForm.detailInfos[index].tradePrice)
  533. * parseFloat(this.inputForm.detailInfos[index].tradeNumber)).toFixed(2)
  534. })
  535. })
  536. }
  537. },
  538. buildTree(nodes, parentId = '0') {
  539. const tree = [];
  540. for (const node of nodes) {
  541. if (node.parentId === parentId) {
  542. const children = this.buildTree(nodes, node.id);
  543. if (children.length) {
  544. node.children = children;
  545. }
  546. tree.push(node);
  547. }
  548. }
  549. return tree;
  550. },
  551. formatDate(date) {
  552. const dateNew = new Date(date); // 将日期字符串转换为 Date 对象
  553. const year = dateNew.getFullYear();
  554. const month = (dateNew.getMonth() + 1).toString().padStart(2, '0');
  555. const day = dateNew.getDate().toString().padStart(2, '0');
  556. return `${year}-${month}-${day}`;
  557. },
  558. isEmpty(value) {
  559. let result = false;
  560. if (value == null || value == undefined) {
  561. result = true;
  562. }
  563. if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
  564. result = true;
  565. }
  566. if (typeof value == "object" && value instanceof Array && value.length === 0) {
  567. result = true;
  568. }
  569. return result;
  570. },
  571. isNotEmpty(value) {
  572. return !this.isEmpty(value)
  573. },
  574. /**
  575. * 判断是否为空
  576. */
  577. isNull(val) {
  578. if (val instanceof Array) {
  579. if (val.length === 0) return true;
  580. } else if (val instanceof Object) {
  581. if (JSON.stringify(val) === "{}") return true;
  582. } else {
  583. if (
  584. val === "null" ||
  585. val == null ||
  586. val === "undefined" ||
  587. val === undefined ||
  588. val === ""
  589. )
  590. return true;
  591. return false;
  592. }
  593. return false;
  594. },
  595. addRow() {
  596. // 点击新增按钮时,向表格中添加一行空数据
  597. this.inputForm.detailInfos.push({
  598. purchaserAgent: this.userInfo.name,
  599. purchaserAgentId: this.userInfo.id, procurementOffice: this.userInfo.officeDTO.name
  600. });
  601. let valueData = this.materialList;
  602. // 将扁平数据转换为树形结构
  603. const result = this.buildTree(valueData);
  604. this.listData = result
  605. },
  606. removeRow(index) {
  607. // 点击删除按钮时,从表格中移除指定行
  608. // this.tableData.splice(index, 1);
  609. this.inputForm.detailInfos.splice(index, 1);
  610. },
  611. formatDateNew(date) {
  612. const year = date.getFullYear();
  613. const month = (date.getMonth() + 1).toString().padStart(2, '0');
  614. const day = date.getDate().toString().padStart(2, '0');
  615. const hours = date.getHours().toString().padStart(2, '0');
  616. const minutes = date.getMinutes().toString().padStart(2, '0');
  617. const seconds = date.getSeconds().toString().padStart(2, '0');
  618. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  619. },
  620. // 采购人下拉弹窗
  621. openUserPullForm(index) {
  622. // 点击 "采购人" 输入框时打开userPullForm页面,传入index用于区分不同的行
  623. // uni.navigateTo({
  624. // url: '/pages/materialManagement/collect/UserPullForm?index=' + index // userPullForm页面的路径
  625. // });
  626. this.$refs.userPicker.open(index, "");
  627. },
  628. handleEvent(data, index, type) {
  629. // 在这里处理子组件传递过来的数据
  630. this.inputForm.detailInfos[index].purchaserAgentId = data.id
  631. this.inputForm.detailInfos[index].purchaserAgent = data.label
  632. this.inputForm.detailInfos[index].procurementOffice = data.parentLabel
  633. this.inputForm.detailInfos[index].deptId = data.parentId
  634. // 进行进一步处理...
  635. },
  636. handleUploadSuccess(file, fileList, index, type) {
  637. if (type === 'detail') {
  638. // 将格式化后的数据设置到 detailInfos 的 fileInfoLost 属性中
  639. this.inputForm.detailInfos[index].fileInfoLost = fileList;
  640. // 遍历 fileList,找到上传成功的文件,设置对应索引的 showFileList2 为 true
  641. fileList.forEach((item, i) => {
  642. if (item === file) {
  643. this.$set(this.showFileList2, i, true);
  644. }
  645. });
  646. } else {
  647. // this.inputForm.files = fileList
  648. fileList.forEach((item, index) => {
  649. if (item === file) {
  650. this.$set(this.showFileList, index, true);
  651. }
  652. });
  653. console.log(this.inputForm.files);
  654. }
  655. // 强制更新视图
  656. this.$forceUpdate();
  657. },
  658. handleRemove(file, fileList, lineIndex, fileindex, type) {
  659. // 处理移除文件逻辑
  660. // file 是移除的文件
  661. // fileList 是当前文件列表
  662. if (type === 'detail') {
  663. this.inputForm.detailInfos[lineIndex].fileInfoLost.splice(fileindex, 1);
  664. this.showFileList2.splice(fileindex, 1); // 从showFileList中移除对应的元素
  665. } else {
  666. this.inputForm.files.splice(fileindex, 1);
  667. this.showFileList.splice(fileindex, 1); // 从showFileList中移除对应的元素
  668. }
  669. // 如果你想要更新文件列表,可以在这里更新 inputForm.fileInfoLost
  670. // this.inputForm.fileInfoLost = fileList;
  671. },
  672. saveForm(callback) {
  673. return new Promise((resolve, reject) => {
  674. // 表单规则验证
  675. // ...
  676. let errors = [];
  677. if (this.isNotEmpty(this.inputForm.purchaseDate)) {
  678. this.inputForm.purchaseDate = this.formatDate(this.inputForm.purchaseDate);
  679. }
  680. if (this.isEmpty(this.inputForm.detailInfos)) {
  681. errors.push('至少填写一条采购详情信息');
  682. } else {
  683. let i = this.inputForm.detailInfos.length;
  684. for (let j = 0; j < i; j++) {
  685. let k = j + 1
  686. if (this.isEmpty(this.inputForm.detailInfos[j].purchaserAgent)) {
  687. this.$message.error('采购详情第' + k + '行请选择采购人')
  688. this.loading = false
  689. return
  690. }
  691. if (this.isEmpty(this.inputForm.detailInfos[j].procurementType)) {
  692. this.$message.error('采购详情第' + k + '行请选择采购类型')
  693. this.loading = false
  694. return
  695. }
  696. if (this.isEmpty(this.inputForm.detailInfos[j].tradeName)) {
  697. this.$message.error('采购详情第' + k + '行请填写商品名称')
  698. this.loading = false
  699. return
  700. }
  701. }
  702. for (let j = 0; j < i; j++) {
  703. for (let k = j + 1; k < i; k++) {
  704. if (this.inputForm.detailInfos[j].procurementType === this.inputForm.detailInfos[k].procurementType) { // 如果采购类型相同
  705. if (this.inputForm.detailInfos[j].tradeName === this.inputForm.detailInfos[k].tradeName) { // 如果商品名称相同
  706. if (this.inputForm.detailInfos[j].supplierName === this.inputForm.detailInfos[k].supplierName) {
  707. this.$message.warning(`采购详情中,同种采购类型、同一供应商的商品名称只能输入一条`)
  708. this.loading = false
  709. throw new Error('采购详情中,同种采购类型、同一供应商的商品名称只能输入一条')
  710. }
  711. }
  712. }
  713. }
  714. }
  715. }
  716. // 计算总价
  717. const tradeTotalPrice = this.inputForm.detailInfos.reduce((total, item) => {
  718. // 将每个 detailInfo 的 priceSum 加到总价中
  719. return total + parseFloat(item.priceSum || 0); // 转换为浮点数并累加,避免字符串拼接
  720. }, 0); // 初始值为 0
  721. if (errors.length > 0) {
  722. // 存在错误,显示提示信息
  723. errors.forEach(error => {
  724. uni.showToast({
  725. title: error,
  726. icon: 'none',
  727. duration: 2000
  728. });
  729. });
  730. reject('Form validation failed');
  731. } else {
  732. // 所有验证通过,执行保存操作
  733. this.$refs.inputForm.validate().then(() => {
  734. uni.showLoading();
  735. this.inputForm.status = '2';
  736. materialManagementService.save(this.inputForm).then(data => {
  737. callback(data.businessTable, data.businessId);
  738. resolve('Form saved successfully');
  739. }).catch(error => {
  740. reject('Save operation failed');
  741. });
  742. }).catch(() => {
  743. reject('Form validation failed');
  744. });
  745. }
  746. });
  747. },
  748. // 修改状态
  749. async updateStatusById(type, callback) {
  750. if (type === 'reject' || type === 'reback') {
  751. materialManagementService.findById(this.inputForm.id).then((data) => {
  752. if (data.status !== '2') { // status的值不等于“审核中”,就弹出提示
  753. this.loading = false
  754. this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
  755. throw new Error()
  756. } else {
  757. if (type === 'reject') {
  758. // 驳回
  759. this.inputForm.status = '4'
  760. }
  761. if (type === 'reback') {
  762. // 撤回
  763. this.inputForm.status = '3'
  764. }
  765. if (type === 'reject' || type === 'reback') {
  766. let param = { status: this.inputForm.status, id: this.inputForm.id }
  767. materialManagementService.updateStatusById(param).then(() => {
  768. this.loading = false
  769. callback()
  770. })
  771. }
  772. }
  773. })
  774. } else if (type === 'hold') {
  775. materialManagementService.findById(this.inputForm.id).then((data) => {
  776. if (data.status !== '4') { // status的值不等于“驳回”就弹出提示
  777. this.loading = false
  778. this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
  779. throw new Error()
  780. } else {
  781. // 终止
  782. let param = { status: '1', id: this.inputForm.id }
  783. materialManagementService.updateStatusById(param).then(() => {
  784. this.loading = false
  785. callback()
  786. })
  787. }
  788. })
  789. }
  790. },
  791. reapplyForm(callback) {
  792. this.loading = true
  793. materialManagementService.findById(this.inputForm.id).then((data) => {
  794. if (data.status !== '4') { // 审核状态不是“驳回”,就弹出提示
  795. this.loading = false
  796. this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
  797. throw new Error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
  798. } else {
  799. this.startFormTrue(callback)
  800. }
  801. })
  802. },
  803. // 送审
  804. async startFormTrue(callback) {
  805. if (this.isNotEmpty(this.inputForm.purchaseDate)) {
  806. this.inputForm.purchaseDate = this.formatDate(this.inputForm.purchaseDate);
  807. }
  808. this.$refs.inputForm.validate().then(res => {
  809. this.inputForm.status = '2'
  810. // 计算总价
  811. const tradeTotalPrice = this.inputForm.detailInfos.reduce((total, item) => {
  812. // 将每个 detailInfo 的 priceSum 加到总价中
  813. return total + parseFloat(item.priceSum || 0); // 转换为浮点数并累加,避免字符串拼接
  814. }, 0); // 初始值为 0
  815. materialManagementService.save(this.inputForm).then((data) => {
  816. this.inputForm.id = data.businessId
  817. callback(data.businessTable, data.businessId, this.inputForm)
  818. this.$refs.inputForm.resetFields()
  819. this.loading = false
  820. }).catch(() => {
  821. this.$refs.inputForm.resetFields()
  822. }).catch((e) => {
  823. })
  824. })
  825. },
  826. // 通过
  827. async agreeForm(callback) {
  828. if (this.isNotEmpty(this.inputForm.purchaseDate)) {
  829. this.inputForm.purchaseDate = this.formatDate(this.inputForm.purchaseDate);
  830. }
  831. this.$refs.inputForm.validate().then(res => {
  832. this.commonApi.getTaskNameByProcInsId(this.inputForm.procInsId).then((data) => {
  833. if (this.isNotEmpty(data)) {
  834. if (data === '公司领导审批') {
  835. this.inputForm.status = '5'
  836. }
  837. }
  838. materialManagementService.save(this.inputForm).then((data) => {
  839. callback(data.businessTable, data.businessId, this.inputForm)
  840. this.$refs.inputForm.resetFields()
  841. this.loading = false
  842. }).catch(() => {
  843. this.loading = false
  844. this.$refs.inputForm.resetFields()
  845. })
  846. })
  847. })
  848. },
  849. // 值改变事件
  850. changeValue() {
  851. let i = this.inputForm.detailInfos.length
  852. for (let j = 0; j < i; j++) {
  853. if (this.isNotEmpty(this.inputForm.detailInfos[j].tradePrice)) {
  854. if (this.isNotEmpty(this.inputForm.detailInfos[j].tradeNumber)) {
  855. // parseFloat(item.account).toFixed(2)
  856. this.inputForm.detailInfos[j].priceSum = parseFloat(parseFloat(this.inputForm.detailInfos[j].tradePrice) * parseFloat(this.inputForm.detailInfos[j].tradeNumber)).toFixed(2)
  857. } else {
  858. this.inputForm.detailInfos[j].priceSum = ''
  859. }
  860. } else {
  861. this.inputForm.detailInfos[j].priceSum = ''
  862. }
  863. }
  864. },
  865. async handleFileClick(file) {
  866. await this.ossService.getTemporaryUrl(file.url).then((data) => {
  867. file.lsUrl = data
  868. })
  869. if (this.isImage(file.name)) {
  870. // 如果是图片文件,则执行放大显示图片的逻辑
  871. this.handleImageClick(file);
  872. } else {
  873. // window.open(file.lsUrl, '_blank')
  874. window.location.href = file.lsUrl
  875. // 如果不是图片文件,则执行其他操作,比如下载文件等
  876. }
  877. },
  878. // 判断文件是否是图片类型
  879. isImage(fileName) {
  880. const ext = fileName.toLowerCase().split('.').pop(); // 获取文件的后缀名
  881. return ['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext); // 判断后缀名是否是图片类型
  882. },
  883. handleImageClick(file) {
  884. // 在点击图片时执行放大显示的逻辑
  885. this.$alert(`<img src="${file.lsUrl}" style="max-width: 100%; max-height: 100%;" />`, '图片详情', {
  886. dangerouslyUseHTMLString: true,
  887. customClass: 'custom-alert'
  888. });
  889. },
  890. handleDelete(file, lineIndex, type) {
  891. // 处理删除文件的逻辑
  892. if (type === 'detail') {
  893. const index = this.inputForm.detailInfos[lineIndex].fileInfoLost.indexOf(file);
  894. if (index !== -1) {
  895. this.inputForm.detailInfos[lineIndex].fileInfoLost.splice(index, 1);
  896. this.showFileList2.splice(index, 1); // 从showFileList中移除对应的元素
  897. }
  898. } else {
  899. // 从文件列表中移除文件
  900. const index = this.inputForm.files.indexOf(file);
  901. if (index !== -1) {
  902. this.inputForm.files.splice(index, 1);
  903. this.showFileList.splice(index, 1); // 从showFileList中移除对应的元素
  904. }
  905. }
  906. },
  907. shouldShowFile(file, index, type) {
  908. if (type === 'detail') {
  909. if (this.inputForm.detailInfos[index].fileInfoLost && this.inputForm.detailInfos[index].fileInfoLost.length > 0) {
  910. // 返回一个布尔值,确定是否显示上传成功后的文件
  911. return this.showFileList2[this.inputForm.detailInfos[index].fileInfoLost.indexOf(file)];
  912. }
  913. } else {
  914. if (this.inputForm.files && this.inputForm.files.length > 0) {
  915. // 返回一个布尔值,确定是否显示上传成功后的文件
  916. return this.showFileList[this.inputForm.files.indexOf(file)];
  917. }
  918. }
  919. return false; // 默认返回 false 或者其他适当的
  920. },
  921. onInputCode(index, event, type) {
  922. const inputValue = event
  923. const formattedValue = this.formatInput(inputValue);
  924. if (type === 'tradePrice') {
  925. this.$set(this.inputForm.detailInfos[index], 'tradePrice', formattedValue)
  926. }
  927. if (type === 'tradeNumber') {
  928. this.$set(this.inputForm.detailInfos[index], 'tradeNumber', formattedValue)
  929. }
  930. if (this.isNotEmpty(this.inputForm.detailInfos[index].tradePrice && this.inputForm.detailInfos[index].tradeNumber)) {
  931. let priceSum =
  932. parseFloat(parseFloat(this.inputForm.detailInfos[index].tradePrice) * parseFloat(this.inputForm.detailInfos[index].tradeNumber)).toFixed(2)
  933. this.$set(this.inputForm.detailInfos[index], 'priceSum', priceSum)
  934. }
  935. },
  936. // 通用的输入限制和格式化方法
  937. formatInput(inputValue, decimalLimit = 2) {
  938. console.log('inputValue', inputValue)
  939. // 如果输入值不是数字或者不是有效的小数,则返回空字符串
  940. if (!/^\d*\.?\d*$/.test(inputValue)) {
  941. return '';
  942. }
  943. // 只保留数字和一个小数点
  944. let value = inputValue.replace(/[^\d.]/g, '');
  945. // 只允许一个小数点
  946. const dotIndex = value.indexOf('.');
  947. if (dotIndex !== -1) {
  948. const substr = value.substr(dotIndex + 1);
  949. if (substr.indexOf('.') !== -1) {
  950. value = value.substr(0, dotIndex + 1) + substr.replace(/\./g, '');
  951. }
  952. }
  953. // 限制小数位数为指定的decimalLimit位数
  954. if (dotIndex !== -1) {
  955. const integerPart = value.substring(0, dotIndex);
  956. const decimalPart = value.substring(dotIndex + 1);
  957. if (decimalPart.length > decimalLimit) {
  958. uni.showToast({
  959. title: '商品数量小数点后只能输入两位,请正确输入!',
  960. icon: 'none',
  961. duration: 2000
  962. });
  963. return ''; // 返回空字符串
  964. }
  965. value = integerPart + '.' + decimalPart;
  966. }
  967. return value;
  968. },
  969. }
  970. }
  971. </script>
  972. <style>
  973. .cu-form-group .title {
  974. min-width: calc(4em + 40px);
  975. }
  976. .custom-alert {
  977. max-width: 80% !important;
  978. max-height: 80% !important;
  979. }
  980. /* 样式示例,您可能需要根据实际情况调整 */
  981. .upload-demo {
  982. width: 40%;
  983. }
  984. </style>