index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. <template>
  2. <div class="pageIndexClass">
  3. <div class="content">
  4. <byTable :source="sourceList.data" :pagination="sourceList.pagination" :config="config" :loading="loading" :selectConfig="selectConfig"
  5. highlight-current-row :action-list="[
  6. {
  7. text: '添加发票',
  8. action: () => openModal('add'),
  9. },
  10. ]" @get-list="getList">
  11. </byTable>
  12. </div>
  13. <el-dialog :title="modalType == 'add' ? '添加发票' : '编辑发票'" v-if="dialogVisible" v-model="dialogVisible" width="1000" v-loading="loadingDialog">
  14. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
  15. <template #information>
  16. <el-table :data="formData.data.invoiceDetailsList" style="width: 100%; margin-top: 16px">
  17. <el-table-column prop="code" label="采购合同" min-width="140" />
  18. <el-table-column prop="amount" label="合同金额" width="120" />
  19. <el-table-column prop="sumInvoiceMoney" label="已收发票金额" width="120" />
  20. <el-table-column label="关联金额" width="140">
  21. <template #default="{ row, $index }">
  22. <el-form-item :prop="'invoiceDetailsList.' + $index + '.money'" :rules="rules.money" :inline-message="true">
  23. <el-input-number onmousewheel="return false;" v-model="row.money" placeholder="请输入关联金额" style="width: 100%" :precision="2"
  24. :controls="false" :min="0" />
  25. </el-form-item>
  26. </template>
  27. </el-table-column>
  28. </el-table>
  29. </template>
  30. </byForm>
  31. <template #footer>
  32. <el-button @click="dialogVisible = false" size="default">取 消</el-button>
  33. <el-button type="primary" @click="submitForm()" size="default">确 定</el-button>
  34. </template>
  35. </el-dialog>
  36. </div>
  37. </template>
  38. <script setup>
  39. import { computed, ref } from "vue";
  40. import byTable from "@/components/byTable/index";
  41. import byForm from "@/components/byForm/index";
  42. import useUserStore from "@/store/modules/user";
  43. import { ElMessage, ElMessageBox } from "element-plus";
  44. const { proxy } = getCurrentInstance();
  45. const invoiceType = ref([]);
  46. const supplierList = ref([]);
  47. const sourceList = ref({
  48. data: [],
  49. pagination: {
  50. total: 0,
  51. pageNum: 1,
  52. pageSize: 10,
  53. keyword: "",
  54. invoiceType: "",
  55. },
  56. });
  57. const loading = ref(false);
  58. const selectConfig = computed(() => {
  59. return [
  60. {
  61. label: "发票类型",
  62. prop: "invoiceType",
  63. data: invoiceType.value,
  64. },
  65. ];
  66. });
  67. const config = computed(() => {
  68. return [
  69. {
  70. attrs: {
  71. label: "业务公司",
  72. prop: "companyName",
  73. width: 110,
  74. },
  75. },
  76. {
  77. attrs: {
  78. label: "供应商",
  79. prop: "supplyName",
  80. width: 250,
  81. },
  82. },
  83. {
  84. attrs: {
  85. label: "发票类型",
  86. prop: "type",
  87. width: 160,
  88. },
  89. render(type) {
  90. let text = "";
  91. if (invoiceType.value && invoiceType.value.length > 0) {
  92. let data = invoiceType.value.filter((item) => item.value == type);
  93. if (data && data.length > 0) {
  94. text = data[0].label;
  95. }
  96. }
  97. return text;
  98. },
  99. },
  100. {
  101. attrs: {
  102. label: "发票金额",
  103. prop: "money",
  104. width: 160,
  105. },
  106. },
  107. {
  108. attrs: {
  109. label: "关联合同",
  110. prop: "purchaseCodes",
  111. },
  112. },
  113. {
  114. attrs: {
  115. label: "操作",
  116. width: "120",
  117. align: "center",
  118. },
  119. renderHTML(row) {
  120. return proxy.isCurrentCompanyData(row.companyId)
  121. ? [
  122. {
  123. attrs: {
  124. label: "修改",
  125. type: "primary",
  126. text: true,
  127. },
  128. el: "button",
  129. click() {
  130. update(row);
  131. },
  132. },
  133. {
  134. attrs: {
  135. label: "删除",
  136. type: "primary",
  137. text: true,
  138. },
  139. el: "button",
  140. click() {
  141. ElMessageBox.confirm(
  142. "此操作将永久删除该数据, 是否继续?",
  143. "提示",
  144. {
  145. confirmButtonText: "确定",
  146. cancelButtonText: "取消",
  147. type: "warning",
  148. }
  149. ).then(() => {
  150. proxy
  151. .post("/invoice/delete", {
  152. id: row.id,
  153. })
  154. .then(() => {
  155. ElMessage({
  156. message: "删除成功",
  157. type: "success",
  158. });
  159. getList();
  160. });
  161. });
  162. },
  163. },
  164. ]
  165. : [];
  166. },
  167. },
  168. ];
  169. });
  170. const getDict = () => {
  171. proxy
  172. .post("/dictTenantData/page", {
  173. pageNum: 1,
  174. pageSize: 999,
  175. dictCode: "invoice_type",
  176. tenantId: useUserStore().user.tenantId,
  177. })
  178. .then((res) => {
  179. if (res.rows && res.rows.length > 0) {
  180. invoiceType.value = res.rows.map((item) => {
  181. return {
  182. label: item.dictValue,
  183. value: item.dictKey,
  184. };
  185. });
  186. }
  187. });
  188. proxy
  189. .post("/supplierInfo/page", { pageNum: 1, pageSize: 999 })
  190. .then((res) => {
  191. if (res.rows && res.rows.length > 0) {
  192. supplierList.value = res.rows.map((item) => {
  193. return {
  194. label: item.name,
  195. value: item.id,
  196. };
  197. });
  198. }
  199. });
  200. };
  201. const getList = async (req) => {
  202. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  203. loading.value = true;
  204. proxy.post("/invoice/page", sourceList.value.pagination).then((res) => {
  205. sourceList.value.data = res.rows;
  206. sourceList.value.pagination.total = res.total;
  207. setTimeout(() => {
  208. loading.value = false;
  209. }, 200);
  210. });
  211. };
  212. getDict();
  213. getList();
  214. const modalType = ref("add");
  215. const dialogVisible = ref(false);
  216. const loadingDialog = ref(false);
  217. const uploadData = ref({});
  218. const submit = ref(null);
  219. const formOption = reactive({
  220. inline: true,
  221. labelWidth: 100,
  222. itemWidth: 100,
  223. rules: [],
  224. });
  225. const formConfig = computed(() => {
  226. return [
  227. {
  228. type: "treeSelect",
  229. prop: "companyId",
  230. label: "业务公司",
  231. data: proxy.useUserStore().allDict["tree_company_data"],
  232. propsTreeLabel: "deptName",
  233. propsTreeValue: "deptId",
  234. itemWidth: 50,
  235. },
  236. {
  237. type: "select",
  238. label: "供应商",
  239. prop: "supplyId",
  240. data: supplierList.value,
  241. fn: (val) => {
  242. changeSupply(val);
  243. },
  244. disabled: formData.data.id,
  245. itemWidth: 50,
  246. },
  247. {
  248. type: "select",
  249. label: "发票类型",
  250. prop: "type",
  251. data: invoiceType.value,
  252. itemWidth: 50,
  253. },
  254. {
  255. type: "number",
  256. prop: "money",
  257. label: "开票金额",
  258. precision: 2,
  259. min: 0,
  260. controls: false,
  261. itemWidth: 50,
  262. },
  263. {
  264. type: "upload",
  265. listType: "text",
  266. accept: "",
  267. prop: "fileList",
  268. label: "上传附件",
  269. },
  270. {
  271. type: "slot",
  272. prop: "information",
  273. slotName: "information",
  274. label: "发票信息",
  275. },
  276. ];
  277. });
  278. const rules = ref({
  279. supplyId: [{ required: true, message: "请选择供应商", trigger: "change" }],
  280. type: [{ required: true, message: "请选择发票类型", trigger: "change" }],
  281. money: [{ required: true, message: "请输入金额", trigger: "blur" }],
  282. companyId: [{ required: true, message: "请选择业务公司", trigger: "change" }],
  283. });
  284. const formData = reactive({
  285. data: {
  286. invoiceDetailsList: [],
  287. },
  288. });
  289. const openModal = (val) => {
  290. modalType.value = val;
  291. formData.data = {
  292. invoiceDetailsList: [],
  293. fileList: [],
  294. };
  295. loadingDialog.value = false;
  296. dialogVisible.value = true;
  297. };
  298. const changeSupply = (val) => {
  299. if (val) {
  300. proxy
  301. .get("/ehsdPurchase/getNoInvoiceListBySupplyId", { supplyId: val })
  302. .then((res) => {
  303. if (res.data && res.data.length > 0) {
  304. formData.data.invoiceDetailsList = res.data.map((item) => {
  305. return {
  306. purchaseId: item.id,
  307. code: item.code,
  308. amount: item.amount,
  309. sumInvoiceMoney: item.sumInvoiceMoney,
  310. money: 0,
  311. remark: "",
  312. };
  313. });
  314. } else {
  315. formData.data.invoiceDetailsList = [];
  316. }
  317. });
  318. } else {
  319. formData.data.invoiceDetailsList = [];
  320. }
  321. };
  322. const uploadFile = async (file) => {
  323. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  324. uploadData.value = res.uploadBody;
  325. file.id = res.id;
  326. file.fileName = res.fileName;
  327. file.fileUrl = res.fileUrl;
  328. return true;
  329. };
  330. const onPreviewFile = (file) => {
  331. window.open(file.raw.fileUrl, "_blank");
  332. };
  333. const submitForm = () => {
  334. submit.value.handleSubmit(() => {
  335. if (
  336. !(
  337. formData.data.invoiceDetailsList &&
  338. formData.data.invoiceDetailsList.length > 0
  339. )
  340. ) {
  341. return ElMessage("该供应商暂无关联合同");
  342. }
  343. let money = 0;
  344. for (let i = 0; i < formData.data.invoiceDetailsList.length; i++) {
  345. money = parseFloat(
  346. Number(money) + Number(formData.data.invoiceDetailsList[i].money)
  347. ).toFixed(2);
  348. }
  349. if (money != formData.data.money) {
  350. return ElMessage("开票金额不等于关联金额");
  351. }
  352. loadingDialog.value = true;
  353. proxy.post("/invoice/" + modalType.value, formData.data).then(
  354. () => {
  355. ElMessage({
  356. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  357. type: "success",
  358. });
  359. dialogVisible.value = false;
  360. getList();
  361. },
  362. (err) => {
  363. console.log(err);
  364. loadingDialog.value = false;
  365. }
  366. );
  367. });
  368. };
  369. const update = (row) => {
  370. modalType.value = "edit";
  371. loadingDialog.value = true;
  372. dialogVisible.value = true;
  373. proxy.post("/invoice/detail", { id: row.id }).then((res) => {
  374. if (res.invoiceDetailsVoList && res.invoiceDetailsVoList.length > 0) {
  375. res.invoiceDetailsList = res.invoiceDetailsVoList.map((item) => {
  376. return {
  377. code: item.purchaseCode,
  378. purchaseId: item.purchaseId,
  379. amount: item.purchaseAmount,
  380. sumInvoiceMoney: item.sumMoney,
  381. money: item.money,
  382. };
  383. });
  384. }
  385. if (res.type) {
  386. res.type = res.type + "";
  387. }
  388. res.fileList = [];
  389. delete res.invoiceDetailsVoList;
  390. formData.data = res;
  391. loadingDialog.value = false;
  392. loadingDialog.value = false;
  393. proxy
  394. .post("/fileInfo/getList", { businessIdList: [row.id] })
  395. .then((fileObj) => {
  396. if (fileObj[row.id] && fileObj[row.id].length > 0) {
  397. formData.data.fileList = fileObj[row.id].map((item) => {
  398. return {
  399. ...item,
  400. name: item.fileName,
  401. url: item.fileUrl,
  402. };
  403. });
  404. } else {
  405. formData.data.fileList = [];
  406. }
  407. });
  408. });
  409. };
  410. </script>
  411. <style lang="scss" scoped>
  412. .tenant {
  413. padding: 20px;
  414. }
  415. ::v-deep(.el-input-number .el-input__inner) {
  416. text-align: left;
  417. }
  418. </style>