app.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. <template>
  2. <hc-new-card>
  3. <template #header>
  4. <div class="w-60">
  5. <hc-search-input v-model="searchForm.name" placeholder="请输入名称关键词" @search="searchClick" />
  6. </div>
  7. </template>
  8. <template #extra>
  9. <el-button hc-btn type="primary" @click="addClick">新增</el-button>
  10. </template>
  11. <hc-table :column="tableColumn" :datas="tableData" :loading="tableLoading" is-new :index-style="{ width: 60 }">
  12. <template #action="{ row }">
  13. <el-link type="warning" @click="editRowClick(row)">修改</el-link>
  14. <el-link type="primary" @click="updateRowClick(row)">升级</el-link>
  15. <el-link type="danger" @click="delRowClick(row)">删除</el-link>
  16. </template>
  17. </hc-table>
  18. <template #action>
  19. <hc-pages :pages="searchForm" @change="pageChange" />
  20. </template>
  21. <!-- 新增/修改 -->
  22. <hc-new-dialog v-model="isDialogShow" widths="400px" is-footer-center :title="dialogTitle" @close="dialogClose">
  23. <el-form ref="formRef" :model="formModel" :rules="formRules" label-position="top" label-width="auto">
  24. <el-form-item label="应用平台:" prop="platform">
  25. <el-input v-model="formModel.platform" clearable placeholder="请输入应用平台" />
  26. </el-form-item>
  27. <el-form-item label="应用名称:" prop="name">
  28. <el-input v-model="formModel.name" clearable placeholder="请输入应用名称" />
  29. </el-form-item>
  30. <el-form-item label="当前版本:" prop="currentVersion">
  31. <el-input v-model="formModel.currentVersion" clearable placeholder="请输入当前版本号" />
  32. </el-form-item>
  33. <el-form-item label="应用说明:">
  34. <el-input v-model="formModel.appExplain" :autosize="{ minRows: 4, maxRows: 8 }" type="textarea" placeholder="请输入应用说明" />
  35. </el-form-item>
  36. </el-form>
  37. <template #footer>
  38. <el-button hc-btn @click="dialogClose">取消</el-button>
  39. <el-button hc-btn type="primary" :loading="submitLoading" @click="dialogSubmit">提交</el-button>
  40. </template>
  41. </hc-new-dialog>
  42. <!-- APP升级列表 -->
  43. <hc-new-dialog v-model="isUpdateDialog" ui="hc-app-update-dialog" widths="700px" is-table @close="updateDialogClose">
  44. <template #header>
  45. <el-button hc-btn type="primary" @click="addUpdateClick">新增版本</el-button>
  46. <div class="hc-update-dialog-title">{{ updateDialogTitle }}</div>
  47. </template>
  48. <hc-table :column="tableUpdateColumn" :datas="tableUpdateData" :loading="tableUpdateLoading" is-new :index-style="{ width: 60 }">
  49. <template #softwareType="{ row }">
  50. {{ row.softwareType === 1 ? '安卓' : 'IOS' }}
  51. </template>
  52. <template #fileType="{ row }">
  53. {{ row.fileType === 0 ? '完整' : 'wgt' }}
  54. </template>
  55. <template #constraintUpdate="{ row }">
  56. {{ row.fileType === 1 ? '是' : '否' }}
  57. </template>
  58. <template #action="{ row }">
  59. <el-link type="warning" @click="editUpdateRow(row)">修改</el-link>
  60. <el-link type="danger" @click="delUpdateRow(row)">删除</el-link>
  61. </template>
  62. </hc-table>
  63. <template #footer>
  64. <hc-pages :pages="searchUpdateForm" @change="pageUpdateChange" />
  65. </template>
  66. </hc-new-dialog>
  67. <!-- 新增/修改 APP升级 -->
  68. <hc-new-dialog v-model="isUpdateFormDialog" widths="550px" is-footer-center :title="updateFormTitle" @close="updateFormDialogClose">
  69. <el-form ref="formUpdateRef" :model="formUpdateModel" :rules="formUpdateRules" label-position="left" label-width="auto">
  70. <el-form-item label="当前版本:" prop="versionNumber">
  71. <el-input v-model="formUpdateModel.versionNumber" clearable placeholder="请输入当前版本号" />
  72. </el-form-item>
  73. <el-form-item label="软件类型:" prop="softwareType">
  74. <el-radio-group v-model="formUpdateModel.softwareType">
  75. <el-radio :label="1">安卓</el-radio>
  76. <el-radio :label="2">ios</el-radio>
  77. </el-radio-group>
  78. </el-form-item>
  79. <el-form-item label="文件类型:" prop="fileType">
  80. <el-radio-group v-model="formUpdateModel.fileType">
  81. <el-radio :label="0">完整安装包</el-radio>
  82. <el-radio :label="1">wgt热更新包</el-radio>
  83. </el-radio-group>
  84. </el-form-item>
  85. <el-form-item label="更新内容:" prop="updateContent">
  86. <el-input v-model="formUpdateModel.updateContent" :autosize="{ minRows: 4, maxRows: 8 }" type="textarea" placeholder="请输入更新内容" />
  87. </el-form-item>
  88. <el-form-item label="文件地址:" prop="fileUrl">
  89. <el-input v-model="formUpdateModel.fileUrl" clearable>
  90. <template #append>
  91. <el-button @click="uploadFile">上传文件</el-button>
  92. </template>
  93. </el-input>
  94. </el-form-item>
  95. <el-form-item label="强制更新:" prop="constraintUpdate">
  96. <el-radio-group v-model="formUpdateModel.constraintUpdate">
  97. <el-radio :label="1"></el-radio>
  98. <el-radio :label="0"></el-radio>
  99. </el-radio-group>
  100. </el-form-item>
  101. </el-form>
  102. <template #footer>
  103. <el-button hc-btn @click="updateFormDialogClose">取消</el-button>
  104. <el-button hc-btn type="primary" :loading="submitUpdateLoading" @click="dialogUpdateSubmit">提交</el-button>
  105. </template>
  106. </hc-new-dialog>
  107. <!-- 上传文件 -->
  108. <hc-upload-file ref="uploadRef" :options="uploadOptions" @success="uploadSuccess" />
  109. </hc-new-card>
  110. </template>
  111. <script setup>
  112. import { nextTick, onActivated, ref } from 'vue'
  113. import { formValidate, getArrValue } from 'js-fast-way'
  114. import { delMessage } from '~uti/tools'
  115. import mainApi from '~api/system/app'
  116. import { getHeader } from 'hc-vue3-ui'
  117. //激活
  118. onActivated(() => {
  119. searchForm.value.current = 1
  120. getTableData()
  121. })
  122. //搜索表单
  123. const searchForm = ref({ current: 1, size: 30, total: 0 })
  124. //搜索
  125. const searchClick = () => {
  126. searchForm.value.current = 1
  127. getTableData()
  128. }
  129. //分页
  130. const pageChange = ({ current, size }) => {
  131. searchForm.value.current = current
  132. searchForm.value.size = size
  133. getTableData()
  134. }
  135. //表格数据
  136. const tableColumn = ref([
  137. { key: 'platform', name: '应用平台' },
  138. { key: 'name', name: '应用名称' },
  139. { key: 'currentVersion', name: '当前版本' },
  140. { key: 'updateTime', name: '更新时间' },
  141. { key: 'action', name: '操作', width: 120, align: 'center' },
  142. ])
  143. //获取表格数据
  144. const tableLoading = ref(false)
  145. const tableData = ref([{}])
  146. const getTableData = async () => {
  147. tableData.value = []
  148. tableLoading.value = true
  149. const { error, code, data } = await mainApi.page({
  150. ...searchForm.value,
  151. total: null,
  152. })
  153. tableLoading.value = false
  154. if (!error && code === 200) {
  155. tableData.value = getArrValue(data['records'])
  156. searchForm.value.total = data['total']
  157. } else {
  158. tableData.value = []
  159. searchForm.value.total = 0
  160. }
  161. }
  162. //新增/修改 弹窗
  163. const isDialogShow = ref(false)
  164. const dialogTitle = ref('')
  165. //菜单表单
  166. const formRef = ref(null)
  167. const formModel = ref({})
  168. const formRules = {
  169. platform: {
  170. required: true,
  171. trigger: 'blur',
  172. message: '请输入应用平台',
  173. },
  174. name: {
  175. required: true,
  176. trigger: 'blur',
  177. message: '请输入应用名称',
  178. },
  179. currentVersion: {
  180. required: true,
  181. trigger: 'blur',
  182. message: '请输入当前版本号',
  183. },
  184. }
  185. //新增
  186. const addClick = () => {
  187. dialogTitle.value = '新增APP'
  188. formModel.value = {}
  189. //显示表单弹窗
  190. nextTick(() => {
  191. isDialogShow.value = true
  192. })
  193. }
  194. //修改
  195. const editRowClick = (row) => {
  196. formModel.value = {}
  197. dialogTitle.value = '修改APP'
  198. formModel.value = { ...row }
  199. //显示表单弹窗
  200. nextTick(() => {
  201. isDialogShow.value = true
  202. })
  203. }
  204. //删除
  205. const delRowClick = (row) => {
  206. delMessage(async () => {
  207. const { code, msg } = await mainApi.del(row.id)
  208. if (code === 200) {
  209. window.$message.success('删除成功')
  210. dialogClose()
  211. getTableData().then()
  212. } else {
  213. window.$message.error(msg ?? '删除失败')
  214. }
  215. })
  216. }
  217. //提交表单
  218. const submitLoading = ref(false)
  219. const dialogSubmit = async () => {
  220. const formRes = await formValidate(formRef.value)
  221. if (!formRes) return false
  222. submitLoading.value = true
  223. //发起请求
  224. let res = {}
  225. if (formModel.value.id) {
  226. res = await mainApi.update(formModel.value)
  227. } else {
  228. res = await mainApi.add(formModel.value)
  229. }
  230. //处理结果
  231. const { error, code, msg } = res
  232. if (!error && code === 200) {
  233. submitLoading.value = false
  234. window?.$message?.success('操作成功')
  235. dialogClose()
  236. getTableData().then()
  237. } else {
  238. window?.$message?.error(msg ?? '操作失败')
  239. }
  240. }
  241. //关闭弹窗
  242. const dialogClose = () => {
  243. isDialogShow.value = false
  244. submitLoading.value = false
  245. formModel.value = {}
  246. }
  247. //升级APP
  248. const isUpdateDialog = ref(false)
  249. const updateDialogTitle = ref('')
  250. const appRowInfo = ref({})
  251. //显示升级弹窗
  252. const updateRowClick = (row) => {
  253. updateDialogTitle.value = `升级 - ${row.name}`
  254. appRowInfo.value = { ...row }
  255. searchUpdateForm.value.current = 1
  256. searchUpdateForm.value.versionId = row.id
  257. nextTick(() => {
  258. isUpdateDialog.value = true
  259. getUpdateTableData()
  260. })
  261. }
  262. //搜索表单
  263. const searchUpdateForm = ref({
  264. current: 1, size: 30, total: 0,
  265. })
  266. //分页
  267. const pageUpdateChange = ({ current, size }) => {
  268. searchUpdateForm.value.current = current
  269. searchUpdateForm.value.size = size
  270. getUpdateTableData()
  271. }
  272. //表格数据
  273. const tableUpdateColumn = ref([
  274. { key: 'softwareType', name: '软件类型', width: 80 },
  275. { key: 'versionNumber', name: '当前版本', width: 100 },
  276. { key: 'fileType', name: '文件类型', width: 80 },
  277. { key: 'constraintUpdate', name: '强制更新', width: 80 },
  278. { key: 'updateDate', name: '更新时间' },
  279. { key: 'action', name: '操作', width: 100, align: 'center' },
  280. ])
  281. //获取表格数据
  282. const tableUpdateLoading = ref(false)
  283. const tableUpdateData = ref([{}])
  284. const getUpdateTableData = async () => {
  285. tableUpdateData.value = []
  286. tableUpdateLoading.value = true
  287. const { error, code, data } = await mainApi.getDetailList({
  288. ...searchUpdateForm.value,
  289. total: null,
  290. })
  291. tableUpdateLoading.value = false
  292. if (!error && code === 200) {
  293. tableUpdateData.value = getArrValue(data['records'])
  294. searchUpdateForm.value.total = data['total']
  295. } else {
  296. tableUpdateData.value = []
  297. searchUpdateForm.value.total = 0
  298. }
  299. }
  300. //新增/修改 弹窗
  301. const isUpdateFormDialog = ref(false)
  302. const updateFormTitle = ref('')
  303. //菜单表单
  304. const formUpdateRef = ref(null)
  305. const formUpdateModel = ref({})
  306. const formUpdateRules = {
  307. versionNumber: {
  308. required: true,
  309. trigger: 'blur',
  310. message: '请输入当前版本号',
  311. },
  312. softwareType: {
  313. required: true,
  314. trigger: 'blur',
  315. message: '请选择软件类型',
  316. },
  317. fileType: {
  318. required: true,
  319. trigger: 'blur',
  320. message: '请选择文件类型',
  321. },
  322. updateContent: {
  323. required: true,
  324. trigger: 'blur',
  325. message: '请输入更新内容',
  326. },
  327. fileUrl: {
  328. required: true,
  329. trigger: 'blur',
  330. message: '请上传文件',
  331. },
  332. constraintUpdate: {
  333. required: true,
  334. trigger: 'blur',
  335. message: '请选择强制更新',
  336. },
  337. }
  338. //新增
  339. const addUpdateClick = () => {
  340. updateFormTitle.value = '新增 - ' + updateDialogTitle.value
  341. formUpdateModel.value = {}
  342. //显示表单弹窗
  343. nextTick(() => {
  344. isUpdateFormDialog.value = true
  345. })
  346. }
  347. //修改
  348. const editUpdateRow = (row) => {
  349. formUpdateModel.value = {}
  350. updateFormTitle.value = '修改 - ' + updateDialogTitle.value
  351. formUpdateModel.value = { ...row }
  352. //显示表单弹窗
  353. nextTick(() => {
  354. isUpdateFormDialog.value = true
  355. })
  356. }
  357. //删除
  358. const delUpdateRow = (row) => {
  359. delMessage(async () => {
  360. const { code, msg } = await mainApi.removeDetail(row.id)
  361. if (code === 200) {
  362. window.$message.success('删除成功')
  363. updateDialogClose()
  364. getUpdateTableData().then()
  365. } else {
  366. window.$message.error(msg ?? '删除失败')
  367. }
  368. })
  369. }
  370. //关闭升级弹窗
  371. const updateDialogClose = () => {
  372. isUpdateDialog.value = false
  373. tableUpdateLoading.value = false
  374. tableUpdateData.value = []
  375. getTableData()
  376. }
  377. //上传文件
  378. const uploadRef = ref(null)
  379. const uploadOptions = ref({
  380. url: '/api/blade-resource/oss/endpoint/put-file2',
  381. accept: '.apk,.wgt',
  382. accept_tip: '只能上传apk或wgt文件',
  383. headers: getHeader(),
  384. multiple: false,
  385. })
  386. //上传文件
  387. const uploadFile = () => {
  388. uploadRef.value?.selectFile()
  389. }
  390. // 文件上传成功的回调
  391. const uploadSuccess = ({ resData }) => {
  392. formUpdateModel.value.fileUrl = resData
  393. uploadRef.value?.setModalShow(false)
  394. }
  395. //提交APP升级表单
  396. const submitUpdateLoading = ref(false)
  397. const dialogUpdateSubmit = async () => {
  398. const formRes = await formValidate(formUpdateRef.value)
  399. if (!formRes) return false
  400. submitUpdateLoading.value = true
  401. //发起请求
  402. let res = {}
  403. if (formUpdateModel.value.id) {
  404. res = await mainApi.updateDetail(formUpdateModel.value)
  405. } else {
  406. res = await mainApi.addDetail(formUpdateModel.value)
  407. }
  408. //处理结果
  409. const { error, code, msg } = res
  410. if (!error && code === 200) {
  411. submitUpdateLoading.value = false
  412. window?.$message?.success('操作成功')
  413. updateFormDialogClose()
  414. getUpdateTableData().then()
  415. } else {
  416. window?.$message?.error(msg ?? '操作失败')
  417. }
  418. }
  419. //关闭升级表单弹窗
  420. const updateFormDialogClose = () => {
  421. isUpdateFormDialog.value = false
  422. submitUpdateLoading.value = false
  423. formUpdateModel.value = {}
  424. }
  425. </script>
  426. <style lang="scss">
  427. .hc-app-update-dialog .el-dialog__headerbtn {
  428. top: 0;
  429. width: 48px;
  430. height: 48px;
  431. }
  432. .hc-update-dialog-title {
  433. position: absolute;
  434. top: 15px;
  435. left: 200px;
  436. right: 200px;
  437. text-align: center;
  438. }
  439. </style>