ImportModal.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. <script setup lang="ts">
  2. import type { FormItemRule } from "element-plus/es/components/form/src/types"
  3. import type { VbFormItem, VbFormRowItem } from "@@@/form/models"
  4. const props = withDefaults(
  5. defineProps<{
  6. options?: any
  7. url?: string
  8. templateUrl?: string
  9. templateName?: string
  10. isAlertError?: boolean
  11. showUpdateCheckbox?: boolean // 是否显示 更新复选框
  12. accept?: string
  13. fileName?: string
  14. headers?: any
  15. title?: string
  16. saveAutoClose?: boolean
  17. formData?: any
  18. formRowItems?: VbFormRowItem[]
  19. formItems?: VbFormItem[]
  20. formRules?: Record<string, FormItemRule[]>
  21. formLabelWidth?: string | number // 表单label宽度
  22. formSize?: "large" | "default" | "small"
  23. gutter?: number
  24. span?: number
  25. formProps?: object
  26. formListeners?: object
  27. modalFormClass?: string
  28. modalFormStyle?: string
  29. isValidateForm?: boolean //验证表单
  30. params?: object | (() => {})
  31. appendToBody?: boolean
  32. }>(),
  33. {
  34. title: "",
  35. headers: () => {
  36. return {
  37. Authorization: "Bearer " + getToken(),
  38. ClientId: import.meta.env.VITE_APP_CLIENT_ID
  39. }
  40. },
  41. accept: ".xlsx, .xls",
  42. templateUrl: "",
  43. templateName: "",
  44. fileName: "file",
  45. isAlertError: true,
  46. appendToBody: true,
  47. showUpdateCheckbox: false,
  48. isValidateForm: true,
  49. saveAutoClose: true,
  50. formLabelWidth: "100px",
  51. formSize: "large",
  52. modalFormClass: "vb-form",
  53. modalFormStyle: ""
  54. }
  55. )
  56. const emits = defineEmits<{
  57. (e: "modelValue:value", v: string): void
  58. (e: "update:formData", data: any): boolean
  59. (e: "onProgress", event: any, file: any, fileList: any): void
  60. (e: "onSuccess", response: any, file: any, fileList: any): void
  61. (e: "onError", error: Error, file: any, fileList: any): void
  62. (e: "onConfirm"): void
  63. }>()
  64. const { formData } = toRefs(props)
  65. const modalFormRef = ref<HTMLFormElement>()
  66. const uploadModalRef = ref()
  67. const uploadRef = ref()
  68. const uploadUpdateSupport = ref(false)
  69. const isUploading = ref(false)
  70. const opts = ref<any>({})
  71. const url = computed(() => {
  72. let queryParams = "?t=" + new Date().getTime()
  73. if (opts.value.showUpdateCheckbox) {
  74. queryParams += `&updateSupport=${uploadUpdateSupport.value}`
  75. }
  76. if (opts.value.params) {
  77. const data =
  78. typeof opts.value.params === "function"
  79. ? opts.value.params()
  80. : typeof opts.value.params === "object"
  81. ? props.params
  82. : {}
  83. for (const key in data) {
  84. if (data.hasOwnProperty(key)) {
  85. queryParams += `&${key}=${data[key]}`
  86. }
  87. }
  88. }
  89. // if (formData.value) {
  90. // for (const key in formData.value) {
  91. // if (formData.value.hasOwnProperty(key)) {
  92. // queryParams += `&${key}=${formData.value[key]}`
  93. // }
  94. // }
  95. // }
  96. return `${opts.value.url}${queryParams}`
  97. })
  98. function submitUpload() {
  99. if (modalFormRef.value && props.isValidateForm) {
  100. modalFormRef.value.validate().then((valid: boolean) => {
  101. if (valid) {
  102. uploadRef.value.submit()
  103. emits("onConfirm")
  104. if (props.saveAutoClose) {
  105. uploadModalRef.value.hide()
  106. }
  107. } else {
  108. console.error("UPLOAD_FORM 验证失败")
  109. }
  110. })
  111. } else {
  112. uploadRef.value.submit()
  113. emits("onConfirm")
  114. if (props.saveAutoClose) {
  115. uploadModalRef.value.hide()
  116. }
  117. }
  118. }
  119. /** 文件上传中处理 */
  120. function handleFileUploadProgress(event: any, file: any, fileList: any) {
  121. isUploading.value = true
  122. message.loading()
  123. emits("onProgress", event, file, fileList)
  124. }
  125. /** 文件上传成功处理 */
  126. function handleFileSuccess(response: any, file: any, fileList: any) {
  127. isUploading.value = false
  128. uploadRef.value.handleRemove(file)
  129. message.alert(
  130. "<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" +
  131. response.msg +
  132. "</div>",
  133. "导入结果",
  134. { dangerouslyUseHTMLString: true }
  135. )
  136. message.closeLoading()
  137. emits("onSuccess", response, file, fileList)
  138. }
  139. function handleFileError(error: Error, file: any, fileList: any) {
  140. message.closeLoading()
  141. if (opts.value.isAlertError) {
  142. message.msgError(error.message)
  143. }
  144. emits("onError", error, file, fileList)
  145. }
  146. function importTemplate() {
  147. download(
  148. opts.value.templateUrl,
  149. `${opts.value.templateName}_TEMPLATE_${new Date().getTime()}.xlsx`
  150. )
  151. }
  152. function getUploadData() {
  153. return formData.value
  154. }
  155. //form表单的插槽 需要_form结尾,并去掉_form传递给VbForm组件
  156. function isFormSlot(v: string | number): string | undefined {
  157. let str
  158. const formSlotSuffix = "_form"
  159. v = v as string
  160. if (v.search(formSlotSuffix) > 0) {
  161. str = v.substring(0, v.length - formSlotSuffix.length)
  162. }
  163. return str
  164. }
  165. function init() {
  166. opts.value = props.options ? Object.assign({}, props, props.options) : props
  167. if (!opts.value.url) {
  168. throw new Error("uploadUrl不能为空!")
  169. }
  170. }
  171. function show() {
  172. uploadModalRef.value.show()
  173. }
  174. onMounted(init)
  175. defineExpose({ show })
  176. </script>
  177. <template>
  178. <VbModal
  179. v-model:modal="uploadModalRef"
  180. :title="opts.title"
  181. :save-auto-close="false"
  182. @confirm="submitUpload"
  183. :append-to-body="appendToBody"
  184. v-bind="$attrs">
  185. <template #body>
  186. <slot name="params_form"></slot>
  187. <VbForm
  188. v-if="formRowItems || formItems"
  189. ref="modalFormRef"
  190. v-model:data="formData"
  191. :row-items="formRowItems"
  192. :items="formItems"
  193. :label-width="formLabelWidth"
  194. :rules="formRules"
  195. :size="formSize"
  196. :class="modalFormClass"
  197. :style="modalFormStyle"
  198. :span="span"
  199. :gutter="gutter"
  200. v-bind="formProps"
  201. v-on="formListeners">
  202. <template v-for="(_, name) in $slots" #[`${isFormSlot(name)}`]>
  203. <slot v-if="isFormSlot(name)" :name="name" />
  204. </template>
  205. </VbForm>
  206. <el-upload
  207. ref="uploadRef"
  208. :limit="1"
  209. :accept="opts.accept"
  210. :headers="opts.headers"
  211. :action="url"
  212. :name="opts.fileName"
  213. :data="getUploadData"
  214. :disabled="isUploading"
  215. :on-progress="handleFileUploadProgress"
  216. :on-success="handleFileSuccess"
  217. :on-error="handleFileError"
  218. :auto-upload="false"
  219. drag>
  220. <el-icon class="el-icon--upload"><upload-filled /></el-icon>
  221. <div class="el-upload__text">
  222. 将文件拖到此处,或
  223. <em>点击上传</em>
  224. </div>
  225. <template #tip>
  226. <div class="el-upload__tip text-center">
  227. <div class="el-upload__tip">
  228. <el-checkbox v-if="opts.showUpdateCheckbox" v-model="uploadUpdateSupport" />
  229. 是否更新已经存在的数据
  230. </div>
  231. <span>仅允许导入{{ opts.accept }}格式文件。</span>
  232. <el-link
  233. v-if="opts.templateUrl"
  234. type="primary"
  235. :underline="false"
  236. style="font-size: 12px; vertical-align: baseline"
  237. @click="importTemplate">
  238. 下载模板
  239. </el-link>
  240. </div>
  241. </template>
  242. </el-upload>
  243. </template>
  244. </VbModal>
  245. </template>