appAdmin.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <template>
  2. <div class="layout-container">
  3. <!-- 菜单栏 -->
  4. <From :form-items="dynamicFormItems" @formSubmitted="handleFormSubmitted" @formReset="handleFormReset"
  5. is_add_button="新增" @addForm="edit" />
  6. <!-- 表格 -->
  7. <div class="layout-container">
  8. <Table @getTableData="changeTableData" v-model:page="page" ref="table" :data="tableData"
  9. @selection-change="handleSelectionChange">
  10. <el-table-column prop="appId" label="应用ID" width="140" />
  11. <el-table-column prop="appName" label="应用名称" width="140" />
  12. <el-table-column prop="superiorName" label="所属应用" width="120" />
  13. <el-table-column prop="ditchName" label="渠道名称" width="140">
  14. <template #default="scope">
  15. <el-tag
  16. type="success"
  17. effect="dark"
  18. v-if="scope.row.ditchName"
  19. >
  20. {{ scope.row.ditchName }}
  21. </el-tag>
  22. </template>
  23. </el-table-column>
  24. <el-table-column prop="nickName" label="所属用户" width="100" />
  25. <el-table-column prop="appType" label="应用类型" width="100">
  26. <template #default="scope">
  27. {{ getDictionaryName("app_type", scope.row.appType) }}
  28. </template>
  29. </el-table-column>
  30. <el-table-column prop="apkUrl" label="下载链接" width="120">
  31. <template #default="scope">
  32. <a v-if="scope.row.apkUrl" :href="scope.row.apkUrl" target="_blank">{{ scope.row.appName }}.apk</a>
  33. </template>
  34. </el-table-column>
  35. <el-table-column prop="qrCode" min-width="130" label="二维码">
  36. <template #default="scope">
  37. <el-image v-if="scope.row.qrCode" style="width: 100px; height: 100px;" :z-index="99999" :src="scope.row.qrCode" fit="fill"
  38. :preview-src-list="[scope.row.qrCode]" preview-teleported="true" />
  39. </template>
  40. </el-table-column>
  41. <el-table-column prop="updateTips" label="更新提示" width="100" />
  42. <el-table-column prop="enabled" label="是否启用" width="100">
  43. <template #default="scope">
  44. {{ getDictionaryName("enabled", scope.row.enabled) }}
  45. </template>
  46. </el-table-column>
  47. <el-table-column label="操作" width="150" fixed="right">
  48. <template #default="scope">
  49. <div class="button">
  50. <el-button class="button-item" type="primary" style="margin-bottom: 5px" @click="edit(scope.row)">
  51. 编辑
  52. </el-button>
  53. <el-popconfirm placement="left" title="确认删除该数据?" @confirm="removeApp(scope.row)">
  54. <template #reference>
  55. <el-button class="button-item" style="margin-bottom: 5px" type="warning">删除</el-button>
  56. </template>
  57. </el-popconfirm>
  58. </div>
  59. </template>
  60. </el-table-column>
  61. </Table>
  62. </div>
  63. <!-- 操作弹窗 -->
  64. <Layer :layer="layer" @confirm="submit(ruleForm)" @close="layer.show = false">
  65. <el-form :model="formEdit" :rules="rules" ref="ruleForm" label-width="130px" style="margin-right: 30px">
  66. <el-row :gutter="5">
  67. <el-col :span="10">
  68. <el-form-item label="应用名称:" required prop="appName">
  69. <el-input v-model="formEdit.appName" placeholder="请输入" clearable />
  70. </el-form-item>
  71. </el-col>
  72. <el-col :span="2"></el-col>
  73. <el-col :span="10">
  74. <el-form-item label="应用类型:" prop="appType">
  75. <el-select v-model="formEdit.appType">
  76. <el-option :value="1" label="Android" />
  77. <el-option :value="2" label="IOS" />
  78. </el-select>
  79. </el-form-item>
  80. </el-col>
  81. </el-row>
  82. <el-row :gutter="5">
  83. <el-col :span="10">
  84. <el-form-item label="出包渠道:" required prop="ditchId">
  85. <el-select v-model="formEdit.ditchId">
  86. <el-option v-for="item in ditchListData" :key="item.ditchId" :value="item.ditchId" :label="item.ditchName" />
  87. </el-select>
  88. </el-form-item>
  89. </el-col>
  90. <el-col :span="2"></el-col>
  91. <el-col :span="10">
  92. <el-form-item label="所属应用:" required prop="superiorId">
  93. <el-select v-model="formEdit.superiorId">
  94. <el-option v-for="item in issuedAppData" :key="item.appId" :value="item.appId" :label="item.appName" />
  95. </el-select>
  96. </el-form-item>
  97. </el-col>
  98. </el-row>
  99. <el-row :gutter="5">
  100. <el-col :span="10">
  101. <el-form-item label="版本号:" prop="versionCode">
  102. <el-input v-model="formEdit.versionCode" placeholder="请输入" clearable />
  103. </el-form-item>
  104. </el-col>
  105. </el-row>
  106. <el-form-item label="更新提示:" prop="updateTips">
  107. <el-input v-model="formEdit.updateTips" type="textarea" placeholder="请输入" clearable />
  108. </el-form-item>
  109. </el-form>
  110. </Layer>
  111. </div>
  112. </template>
  113. <script setup>
  114. import { onBeforeMount, ref, reactive } from "vue";
  115. import { ElMessage } from "element-plus";
  116. import { useGetDictList } from "@/hooks/useGetDictList.js";
  117. import {
  118. appList,
  119. saveOrUpdate,
  120. delApp, issuedApps
  121. } from "@/api/formworkErection.js";
  122. import { ditchList } from '@/api/outBagModule.js'
  123. import From from "@/components/from/index.vue";
  124. import Table from "@/components/table/index.vue";
  125. import Layer from "@/components/layer/index.vue";
  126. const { loadDictData, getDictionaryName } = useGetDictList();
  127. const tableData = ref([]);
  128. // 分页参数, 供table使用
  129. const page = reactive({
  130. pageNum: 1,
  131. pageSize: 20,
  132. total: 0,
  133. });
  134. const formSearch = ref({
  135. appName: null,
  136. channelName: null,
  137. appType: null,
  138. page: 1, // 当前页码
  139. limit: 20, // 当前页数量(查询量)
  140. });
  141. const dynamicFormItems = ref([]);
  142. onBeforeMount(() => {
  143. settingData();
  144. getList();
  145. getDitchList();
  146. getIssuedAppList()
  147. });
  148. // 获取缓存数据设置筛选数据
  149. const settingData = () => {
  150. loadDictData().then(() => {
  151. dynamicFormItems.value = [
  152. {
  153. label: "应用名称",
  154. prop: "appName",
  155. type: "input",
  156. needEnterEvent: true
  157. },
  158. {
  159. label: "应用类型",
  160. prop: "appType",
  161. type: "select",
  162. options: [
  163. {
  164. label: "全部",
  165. value: null,
  166. },
  167. {
  168. label: "Android",
  169. value: 1,
  170. },
  171. {
  172. label: "IOS",
  173. value: 2,
  174. },
  175. ],
  176. },
  177. ];
  178. });
  179. };
  180. // 获取出包渠道
  181. const ditchListData = ref([])
  182. const getDitchList = async() => {
  183. let res = await ditchList({
  184. page: 1,
  185. limit: 999,
  186. })
  187. ditchListData.value = res.data
  188. }
  189. const issuedAppData = ref([])
  190. const getIssuedAppList = async ()=>{
  191. let res = await issuedApps({})
  192. issuedAppData.value = res.data
  193. }
  194. function findByDitchName(ditchId) {
  195. return ditchListData.value.find(item => item.ditchId === ditchId)
  196. }
  197. // 分页数据
  198. const getList = async () => {
  199. let res = await appList({ ...formSearch.value });
  200. tableData.value = res.data;
  201. page.total = res.pageMeta.total;
  202. };
  203. const changeTableData = () => {
  204. formSearch.value.page = page.pageNum;
  205. formSearch.value.limit = page.pageSize;
  206. // 分页切换
  207. getList();
  208. };
  209. // 搜索
  210. const handleFormSubmitted = (formData) => {
  211. console.log("接收到子组件传递的数据", formData);
  212. formSearch.value.page = 1;
  213. formSearch.value.limit = 20;
  214. formSearch.value.channelName = formData?.channelName;
  215. formSearch.value.appName = formData?.appName;
  216. formSearch.value.appType = formData?.appType;
  217. getList();
  218. };
  219. // 表单重置
  220. const handleFormReset = () => {
  221. formSearch.value = {
  222. appName: null,
  223. channelName: null,
  224. appType: null,
  225. page: 1, // 当前页码
  226. limit: 20, // 当前页数量(查询量)
  227. };
  228. getList();
  229. };
  230. // 选择监听器
  231. const handleSelectionChange = (val) => {
  232. context.emit("selection-change", val);
  233. };
  234. // 弹窗
  235. const layer = ref({
  236. show: false,
  237. title: "新增App",
  238. showButton: true,
  239. width: "60vw",
  240. edit: false,
  241. });
  242. const formEdit = ref({
  243. ditchId: null, //渠道ID
  244. ditchName: '',//渠道名称
  245. category: "",
  246. sub_category: "",
  247. versionCode: "",
  248. updateTips: "",
  249. appId: "",
  250. appName: "",
  251. qrCode: "",
  252. apkUrl: "",
  253. superiorId: '',
  254. });
  255. const edit = (row) => {
  256. ruleForm.value?.resetFields();
  257. if (row) {
  258. layer.value.title = "编辑APP";
  259. layer.value.edit = true;
  260. formEdit.value = row;
  261. formEdit.value.ditchId = Number(row.ditchId)
  262. } else {
  263. layer.value.title = "新增APP";
  264. layer.value.edit = false;
  265. formEdit.value = {};
  266. }
  267. layer.value.show = true;
  268. };
  269. const ruleForm = ref(null);
  270. const rules = reactive({
  271. ditchId: [
  272. { required: true, message: "请选择出包渠道", trigger: "change" },
  273. ],
  274. superiorId: [
  275. { required: true, message: "请选择所属应用", trigger: "change" },
  276. ],
  277. appName: [
  278. { required: true, message: "请输入应用名称", trigger: "blur" },
  279. ],
  280. appType: [
  281. { required: true, message: "请输入应用类型", trigger: "blur" },
  282. ],
  283. versionCode: [
  284. { required: true, message: "请输入版本号", trigger: "blur" },
  285. ],
  286. });
  287. const submit = async (formEl) => {
  288. await formEl.validate(async (valid, fields) => {
  289. if (formEdit.value.store_on_sale === 2 && !formEdit.value.store_url && !formEdit.value.store_type) {
  290. ElMessage.error('上架商店或商店链接不能为空')
  291. return
  292. }
  293. if (valid) {
  294. let item = findByDitchName(formEdit.value.ditchId)
  295. formEdit.value.ditchName = item.ditchName
  296. // 提交内容
  297. if (layer.value.edit) {
  298. //api修改需要uuid
  299. formEdit.value.uuid = formEdit.value.appId;
  300. }
  301. const result = await saveOrUpdate({ ...formEdit.value });
  302. console.log(result)
  303. if (result.code === 200) {
  304. if (layer.value.edit) {
  305. ElMessage.success("修改成功");
  306. layer.value.show = false;
  307. } else {
  308. ElMessage.success("新增成功");
  309. layer.value.show = false;
  310. }
  311. handleFormSubmitted();
  312. } else {
  313. ElMessage.error(result.msg);
  314. }
  315. } else {
  316. console.log("error submit!", fields);
  317. }
  318. });
  319. };
  320. // 删除
  321. const removeApp = async (row) => {
  322. await delApp({ appId: row.appId }).then((res) => {
  323. ElMessage.success("删除成功");
  324. handleFormSubmitted();
  325. });
  326. };
  327. </script>
  328. <style scoped lang="scss">
  329. .layout-container {
  330. .card {
  331. .title {
  332. margin-bottom: 10px;
  333. font-weight: 600;
  334. }
  335. display: flex;
  336. flex-direction: column;
  337. align-items: start;
  338. width: calc(100% - 60px);
  339. margin: 30px 30px 0;
  340. }
  341. .button {
  342. display: flex;
  343. flex-direction: column;
  344. .button-item {
  345. margin: 4px;
  346. }
  347. }
  348. }
  349. .el-icon.avatar-uploader-icon {
  350. font-size: 28px;
  351. color: #8c939d;
  352. width: 100px;
  353. height: 100px;
  354. text-align: center;
  355. border: 1px solid #e4e7ed;
  356. }
  357. :deep(.el-image-viewer__wrapper) {
  358. z-index: 9999 !important;
  359. }
  360. </style>