project-form.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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="769px"
  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="logo" :rules="[{ required: true, message: '请上传项目图标', trigger: ['blur', 'change'] }]">
  16. <el-upload class="avatar-uploader"
  17. ref="uploadRef"
  18. :data="{ fileDirectory: state.fileDirectory }"
  19. :action="uploadAction"
  20. :headers="uploadHeaders"
  21. :show-file-list="false"
  22. :on-success="onSuccess"
  23. :on-error="onError">
  24. <img v-if="form.logo" :src="form.logo" class="avatar">
  25. <i v-else class="el-icon-plus avatar-uploader-icon"></i>
  26. </el-upload>
  27. </el-form-item>
  28. </el-col>
  29. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  30. <el-form-item label="项目名称" prop="name" :rules="[{ required: true, message: '请输入项目名称', trigger: ['blur', 'change'] }]">
  31. <el-input v-model="form.name" autocomplete="off" />
  32. </el-form-item>
  33. </el-col>
  34. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  35. <el-form-item label="结算周期" prop="code" :rules="[{ required: true, message: '请输入结算周期', trigger: ['blur', 'change'] }]">
  36. <el-input v-model="form.code" autocomplete="off" />
  37. </el-form-item>
  38. </el-col>
  39. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  40. <el-form-item label="最高佣金" prop="realName" :rules="[{ required: true, message: '请输入最高佣金', trigger: ['blur', 'change'] }]">
  41. <el-input v-model="form.realName" autocomplete="off" />
  42. </el-form-item>
  43. </el-col>
  44. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  45. <el-form-item label="项目简介" prop="realName" :rules="[{ required: true, message: '请输入最高佣金', trigger: ['blur', 'change'] }]">
  46. <el-input v-model="form.description" clearable type="textarea" />
  47. </el-form-item>
  48. </el-col>
  49. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  50. <el-form-item label="项目价格" prop="realName" :rules="[{ required: true, message: '请输入最高佣金', trigger: ['blur', 'change'] }]">
  51. <el-form :inline="true" ref="formPrice" :model="state.formPrice" class="demo-form-inline">
  52. <el-form-item label="结算标准">
  53. <el-input v-model="state.formPrice.name"></el-input>
  54. </el-form-item>
  55. <el-form-item label="价格">
  56. <el-input v-model="state.formPrice.price"></el-input>
  57. </el-form-item>
  58. <el-form-item>
  59. <el-button type="primary">添加</el-button>
  60. </el-form-item>
  61. </el-form>
  62. </el-form-item>
  63. <el-form-item label="" prop="realName" :rules="[{ required: true, message: '请输入最高佣金', trigger: ['blur', 'change'] }]">
  64. <el-table :data="state.form.prices" row-key="id" height="'100%'" style="width: 100%; height: 100%">
  65. <el-table-column type="index" width="80" label="序号"></el-table-column>
  66. <el-table-column prop="name" label="结算标准" min-width="140" show-overflow-tooltip/>
  67. <el-table-column prop="price" label="价格" width="100" show-overflow-tooltip/>
  68. <!-- <el-table-column label="操作" width="140" header-align="center" align="center" fixed="right">
  69. <template #default="{ row }">
  70. <el-button v-auth="'api:admin:tenant:update'" icon="ele-EditPen" size="small" text type="primary"
  71. >删除</el-button>
  72. </template>
  73. </el-table-column> -->
  74. </el-table>
  75. </el-form-item>
  76. </el-col>
  77. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  78. <el-form-item label="项目详情">
  79. <el-input v-model="form.description" clearable type="textarea" />
  80. </el-form-item>
  81. </el-col>
  82. </el-row>
  83. </el-form>
  84. <template #footer>
  85. <span class="dialog-footer">
  86. <el-button @click="onCancel" size="default">取 消</el-button>
  87. <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
  88. </span>
  89. </template>
  90. </el-dialog>
  91. </div>
  92. </template>
  93. <script lang="ts" setup name="admin/project/form">
  94. import { reactive, toRefs, getCurrentInstance, ref, computed } from 'vue'
  95. import { ProjectAddInput, TenantUpdateInput } from '/@/api/admin/data-contracts'
  96. import { ProjectApi } from '/@/api/admin/project'
  97. import type { UploadInstance, UploadProps, UploadFile } from 'element-plus'
  98. import eventBus from '/@/utils/mitt'
  99. import { ElMessage } from 'element-plus'
  100. import { useUserInfo } from '/@/stores/userInfo'
  101. const storesUserInfo = useUserInfo()
  102. const uploadRef = ref<UploadInstance>()
  103. defineProps({
  104. title: {
  105. type: String,
  106. default: '',
  107. },
  108. })
  109. const { proxy } = getCurrentInstance() as any
  110. const formRef = ref()
  111. const state = reactive({
  112. showDialog: false,
  113. sureLoading: false,
  114. form: {} as ProjectAddInput & TenantUpdateInput,
  115. fileList: [] as UploadFile[],
  116. fileDirectory:'project',
  117. token: storesUserInfo.getToken(),
  118. formPrice: {
  119. name: "",
  120. price:""
  121. }
  122. })
  123. const { form } = toRefs(state)
  124. // const getPkgs = async () => {
  125. // const res = await new PkgApi().getList().catch(() => {
  126. // state.pkgData = []
  127. // })
  128. // state.pkgData = res?.data ?? []
  129. // }
  130. // 打开对话框
  131. const open = async (row: any = {}) => {
  132. // await getPkgs()
  133. if (row.id > 0) {
  134. const res = await new ProjectApi().get({ id: row.id }, { loading: true }).catch(() => {
  135. proxy.$modal.closeLoading()
  136. })
  137. if (res?.success) {
  138. state.form = res.data as ProjectAddInput & TenantUpdateInput
  139. }
  140. } else {
  141. state.form = { pkgIds: [] as number[], enabled: true } as ProjectAddInput & TenantUpdateInput
  142. }
  143. state.showDialog = true
  144. }
  145. // //手机号失去焦点
  146. // const onBlurMobile = () => {
  147. // if (!state.form.userName && state.form.phone && isMobile(state.form.phone)) {
  148. // state.form.userName = state.form.phone
  149. // }
  150. // }
  151. // 取消
  152. const onCancel = () => {
  153. state.showDialog = false
  154. }
  155. // 确定
  156. const onSure = () => {
  157. formRef.value.validate(async (valid: boolean) => {
  158. if (!valid) return
  159. state.sureLoading = true
  160. let res = {} as any
  161. if (state.form.id != undefined && state.form.id > 0) {
  162. res = await new ProjectApi().update(state.form, { showSuccessMessage: true }).catch(() => {
  163. state.sureLoading = false
  164. })
  165. } else {
  166. res = await new ProjectApi().add(state.form, { showSuccessMessage: true }).catch(() => {
  167. state.sureLoading = false
  168. })
  169. }
  170. state.sureLoading = false
  171. if (res?.success) {
  172. eventBus.emit('refreshTenant')
  173. state.showDialog = false
  174. }
  175. })
  176. }
  177. const uploadAction = computed(() => {
  178. return import.meta.env.VITE_API_URL + '/api/admin/file/upload-file'
  179. })
  180. const uploadHeaders = computed(() => {
  181. return { Authorization: 'Bearer ' + state.token }
  182. })
  183. // 上传成功
  184. const onSuccess: UploadProps['onSuccess'] = (response) => {
  185. if (response?.success) {
  186. state.form.logo = response.data.linkUrl;
  187. }
  188. }
  189. //上传失败
  190. const onError: UploadProps['onError'] = (error) => {
  191. let message = ''
  192. if (error.message) {
  193. try {
  194. message = JSON.parse(error.message)?.msg
  195. } catch (err) {
  196. message = error.message || ''
  197. }
  198. }
  199. if (message)
  200. ElMessage({
  201. message: message,
  202. type: 'error',
  203. })
  204. }
  205. //
  206. // const cellEdit = (row, colum, cell, event) => {
  207. // state.showDialog = false
  208. // }
  209. // const changeData=(value) =>{
  210. // const reg = /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g
  211. // if (!reg.test(value.kpi.value)) {
  212. // return this.$message.error('只能输入数字')
  213. // } else if (value.kpi.value > 1000000000) {
  214. // return this.$message.error('输入数字过大')
  215. // }
  216. // let params = {
  217. // feeKpi: value.kpi.value,
  218. // meetingId: value.id.value,
  219. // paperKpi: 0,
  220. // registerKpi: 0,
  221. // viewKpi: 0,
  222. // type: 1
  223. // };
  224. // let { data } = await setUpMeeting(params);
  225. // if (data.code == 0) {
  226. // // this.$message.success('设置成功');
  227. // value.kpi.edit = false;
  228. // }
  229. // }
  230. defineExpose({
  231. open,
  232. })
  233. </script>
  234. <style>
  235. .avatar-uploader .el-upload {
  236. border: 1px dashed #d9d9d9;
  237. border-radius: 6px;
  238. cursor: pointer;
  239. position: relative;
  240. overflow: hidden;
  241. }
  242. .avatar-uploader .el-upload:hover {
  243. border-color: #409EFF;
  244. }
  245. .avatar-uploader-icon {
  246. font-size: 28px;
  247. color: #8c939d;
  248. width: 100px;
  249. height: 100px;
  250. line-height: 100px;
  251. text-align: center;
  252. }
  253. .avatar {
  254. width: 100px;
  255. height: 100px;
  256. display: block;
  257. }</style>