banner-form.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <template>
  2. <div>
  3. <el-dialog
  4. v-model="state.showDialog"
  5. destroy-on-close
  6. :title="title"
  7. draggable
  8. :close-on-click-modal="false"
  9. :close-on-press-escape="false"
  10. width="500px"
  11. >
  12. <el-form ref="formRef" :model="form" size="default" label-width="80px">
  13. <el-row :gutter="35">
  14. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  15. <el-form-item label="活动名称" prop="name" :rules="[{ required: true, message: '请输入活动名称', trigger: ['blur', 'change'] }]">
  16. <el-input v-model="form.name" autocomplete="off" placeholder="活动名称"/>
  17. </el-form-item>
  18. </el-col>
  19. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  20. <el-form-item label="跳转方式">
  21. <el-select v-model="form.skipWay" prop="skipWay" placeholder="跳转方式">
  22. <el-option label="请选择" value="0"></el-option>
  23. <el-option label="文章详情" value="1"></el-option>
  24. <el-option label="项目详情" value="2"></el-option>
  25. </el-select>
  26. </el-form-item>
  27. </el-col>
  28. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  29. <el-form-item label="跳转参数" prop="skipContent">
  30. <el-input v-model="form.skipContent" autocomplete="off" placeholder="文章ID或项目ID(不填写则无跳转)"/>
  31. </el-form-item>
  32. </el-col>
  33. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  34. <el-form-item label="活动图片(690X260)" prop="imgUrl" :rules="[{ required: true, message: '请上传活动图片'}]">
  35. <el-upload class="avatar-uploader"
  36. :data="{ fileDirectory: state.fileDirectory }"
  37. :action="ImgAction"
  38. :headers="imgHeaders"
  39. :show-file-list="false"
  40. :on-success="onImgSuccess"
  41. :on-error="onImgError">
  42. <img v-if="form.imgUrl" :src="form.imgUrl" class="avatar">
  43. <i v-else class="el-icon-plus avatar-uploader-icon"></i>
  44. </el-upload>
  45. </el-form-item>
  46. </el-col>
  47. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  48. <el-form-item label="排序" prop="rank" >
  49. <el-input v-model="form.rank" autocomplete="off" placeholder="数值越大越靠前"/>
  50. </el-form-item>
  51. </el-col>
  52. </el-row>
  53. </el-form>
  54. <template #footer>
  55. <span class="dialog-footer">
  56. <el-button @click="onCancel" size="default">取 消</el-button>
  57. <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
  58. </span>
  59. </template>
  60. </el-dialog>
  61. </div>
  62. </template>
  63. <script lang="ts" setup name="admin/banner/form">
  64. // import { stat } from 'fs'
  65. import { reactive, toRefs, getCurrentInstance, ref, computed } from 'vue'
  66. import { BannerAddInput, BannerUpdateInput } from '/@/api/admin/data-contracts'
  67. import { BannerApi } from '/@/api/admin/Banner'
  68. import eventBus from '/@/utils/mitt'
  69. import { useUserInfo } from '/@/stores/userInfo'
  70. import pinia from '/@/stores/index'
  71. import { AxiosResponse } from 'axios'
  72. const storesUserInfo = useUserInfo(pinia)
  73. defineProps({
  74. title: {
  75. type: String,
  76. default: '',
  77. },
  78. })
  79. const { proxy } = getCurrentInstance() as any
  80. const formRef = ref()
  81. const state = reactive({
  82. showDialog: false,
  83. sureLoading: false,
  84. form: {} as BannerAddInput & BannerUpdateInput,
  85. token: storesUserInfo.getToken(),
  86. fileDirectory:'banners',
  87. imgLoading:false
  88. })
  89. const { form } = toRefs(state)
  90. // 打开对话框
  91. const open = async (row: any = {}) => {
  92. if (row.id > 0) {
  93. const res = await new BannerApi().get({ id: row.id }, { loading: true }).catch(() => {
  94. proxy.$modal.closeLoading()
  95. })
  96. if (res?.success) {
  97. state.form = res.data as BannerAddInput & BannerUpdateInput
  98. }
  99. } else {
  100. state.form = {} as BannerAddInput & BannerUpdateInput
  101. }
  102. state.showDialog = true
  103. }
  104. // 取消
  105. const onCancel = () => {
  106. state.showDialog = false
  107. }
  108. // 确定
  109. const onSure = () => {
  110. formRef.value.validate(async (valid: boolean) => {
  111. if (!valid) return
  112. state.sureLoading = true
  113. let res = {} as any
  114. if (state.form.id != undefined && state.form.id > 0) {
  115. res = await new BannerApi().update(state.form, { showSuccessMessage: true }).catch(() => {
  116. state.sureLoading = false
  117. })
  118. } else {
  119. res = await new BannerApi().add(state.form, { showSuccessMessage: true }).catch(() => {
  120. state.sureLoading = false
  121. })
  122. }
  123. state.sureLoading = false
  124. if (res?.success) {
  125. eventBus.emit('refreshBanner')
  126. state.showDialog = false
  127. }
  128. })
  129. }
  130. // 上传请求url
  131. const ImgAction = computed(() => {
  132. return import.meta.env.VITE_API_URL + '/api/admin/file/upload-file'
  133. })
  134. // 上传请求头部
  135. const imgHeaders = computed(() => {
  136. return { Authorization: 'Bearer ' + state.token }
  137. })
  138. // 上传头像成功
  139. const onImgSuccess = (res: AxiosResponse) => {
  140. state.imgLoading = false
  141. if (!res?.success) {
  142. if (res.msg) {
  143. proxy.$modal.msgError(res.msg)
  144. }
  145. return
  146. }
  147. state.form.imgUrl = res?.data?.linkUrl
  148. }
  149. // 上传头像失败
  150. const onImgError = (error: any) => {
  151. state.imgLoading = false
  152. let message = ''
  153. if (error.message) {
  154. try {
  155. message = JSON.parse(error.message)?.msg
  156. } catch (err) {
  157. message = error.message || ''
  158. }
  159. }
  160. if (message) proxy.$modal.msgError(message)
  161. }
  162. defineExpose({
  163. open,
  164. })
  165. </script>
  166. <style>
  167. .avatar-uploader .el-upload {
  168. border: 1px dashed #d9d9d9;
  169. border-radius: 6px;
  170. cursor: pointer;
  171. position: relative;
  172. overflow: hidden;
  173. }
  174. .avatar-uploader .el-upload:hover {
  175. border-color: #409EFF;
  176. }
  177. .avatar-uploader-icon {
  178. font-size: 28px;
  179. color: #8c939d;
  180. width: 300px;
  181. height: 120px;
  182. line-height: 100px;
  183. text-align: center;
  184. }
  185. .avatar {
  186. width: 300px;
  187. height: 120px;
  188. display: block;
  189. }
  190. </style>