actEdit.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. <template>
  2. <view class="body">
  3. <view class="content uni-column">
  4. <view class="uni-column uni-jcc top">
  5. <my-topbar :title="title" :showBack="true" @btnBackClick="btnBack"></my-topbar>
  6. <view class="top-content uni-row">
  7. </view>
  8. </view>
  9. <view class="main uni-column">
  10. <uni-forms ref="form" class="form" :modelValue="formData" :rules="checkRules">
  11. <uni-forms-item label="赛事名称" name="compName">
  12. <uni-easyinput maxlength="25" placeholder="请输入赛事名称 (5~25字)" v-model="formData.compName" :disabled="pubState > 1 ? true : false" />
  13. </uni-forms-item>
  14. <uni-forms-item label="赛事起始时间" name="compBeginTime">
  15. <uni-datetime-picker v-model="formData.compBeginTime" type="datetime" placeholder="选择赛事起始时间" />
  16. </uni-forms-item>
  17. <uni-forms-item label="赛事截止时间" name="compEndTime">
  18. <uni-datetime-picker v-model="formData.compEndTime" type="datetime" placeholder="选择赛事截止时间" />
  19. </uni-forms-item>
  20. <uni-forms-item label="赛事简介" name="description">
  21. <uni-easyinput type="textarea" autoHeight maxlength="500" v-model="formData.description"
  22. placeholder="请输入赛事简介 (10~500字)" :disabled="pubState > 1 ? true : false" />
  23. </uni-forms-item>
  24. <uni-forms-item label="活动规则" name="rules">
  25. <uni-easyinput type="textarea" autoHeight maxlength="500" v-model="formData.rules"
  26. placeholder="请输入活动规则 (10~500字,可为空)" :disabled="pubState > 1 ? true : false" />
  27. </uni-forms-item>
  28. <uni-forms-item label="赛事LOGO" name="matchLogo">
  29. <uni-file-picker v-model="matchLogoObj" :auto-upload="false" limit="1" :title="pubState > 1 ? '' : '请选择赛事的LOGO图片 (可为空)'"
  30. :sizeType="['original', 'compressed']" file-mediatype="image"
  31. file-extname="jpg,jpeg,png,gif" @select="onLogoUploadSelect"
  32. @delete="onLogoUploadDelete" :readonly="pubState > 1 ? true : false"></uni-file-picker>
  33. </uni-forms-item>
  34. <uni-forms-item label="赛事场地" name="mapId">
  35. <e-select v-model="formData.mapId" :options="mapRs" :props="mapSelectionProps" clearable
  36. maxHeight="40vh" :placeholder="'请选择赛事场地(可输入关键字)'" @getText="getMapSelectText"
  37. @change="mapSelectChange" :disabled="pubState > 1 ? true : false"></e-select>
  38. </uni-forms-item>
  39. <uni-forms-item label="赛事方案" name="planId">
  40. <e-select v-model="formData.planId" :options="planRs" :props="planSelectionProps" clearable
  41. maxHeight="40vh" :placeholder="'请选择赛事方案'" @getText="getPlanSelectText"
  42. @change="planSelectChange" :disabled="pubState > 1 ? true : false"></e-select>
  43. </uni-forms-item>
  44. <uni-forms-item label="联系人姓名" name="contactName">
  45. <uni-easyinput maxlength="20" placeholder="请输入联系人姓名" v-model="formData.contactName" />
  46. </uni-forms-item>
  47. <uni-forms-item label="联系人电话" name="phone">
  48. <uni-easyinput maxlength="11" placeholder="请输入联系人电话" v-model="formData.phone" />
  49. </uni-forms-item>
  50. </uni-forms>
  51. <view class="uni-row uni-jcse" style="width: 90%;">
  52. <button class="button" @click="btnBack">返回</button>
  53. <button class="button button-save" @click="saveClick">保存</button>
  54. <!-- <button class="button button-submit" @click="submitClick">发布</button> -->
  55. </view>
  56. </view>
  57. </view>
  58. </view>
  59. </template>
  60. <script>
  61. import {
  62. mapState,
  63. mapGetters
  64. } from 'vuex';
  65. import tools from '/utils/tools.js';
  66. // import { tplStyleList, userLevel, pubState } from '/utils/define.js';
  67. import {
  68. apiCompInfoDetail,
  69. apiCompInfoEdit,
  70. apiUploadFiles,
  71. apiSelectSsctQuery,
  72. apiSelectMapQuery,
  73. apiSelectPlanQuery,
  74. checkResCode
  75. } from '/utils/api.js';
  76. export default {
  77. data() {
  78. return {
  79. queryObj: {},
  80. queryString: "",
  81. from: "",
  82. compId: 0, // 赛事ID
  83. pubState: 0, //发布状态 0:审核中 1:内测 2:已发布
  84. title: "赛事修改",
  85. mapSelectionProps: {
  86. text: 'Label',
  87. value: 'Value',
  88. },
  89. planSelectionProps: {
  90. text: 'Label',
  91. value: 'Value',
  92. },
  93. mapRs: [], // 地图(场地)信息集合
  94. planRs: [], // 方案信息集合
  95. matchLogoObj: {},
  96. formData: {
  97. matchLogo: "", // 赛事LOGO
  98. matchBanner: "", // 赛事BANNER
  99. compName: "", // 赛事名称
  100. description: "", // 赛事简介
  101. rules: "", // 活动规则
  102. contactName: "", // 联系人姓名
  103. phone: "", // 联系人电话
  104. regBeginTime: "", // 报名开始时间 (格式 2025-01-02 15:42:35)
  105. regBeginSecond: "", // 报名开始时间戳,单位 秒
  106. regEndTime: "", // 报名结束时间
  107. regEndSecond: "", // 报名结束时间戳,单位 秒
  108. compBeginTime: "", // 赛事开始时间
  109. compBeginSecond: "", // 赛事开始时间戳,单位 秒
  110. compEndTime: "", // 赛事结束时间
  111. compEndSecond: "", // 赛事结束时间戳,单位 秒
  112. mapId: null, // 场地ID
  113. planId: null // 方案ID
  114. },
  115. checkRules: {
  116. compName: {
  117. rules: [{
  118. required: true,
  119. errorMessage: '请输入赛事名称',
  120. },
  121. {
  122. minLength: 5,
  123. maxLength: 25,
  124. errorMessage: '赛事名称长度在 {minLength} 到 {maxLength} 个字符',
  125. }
  126. ]
  127. },
  128. compBeginTime: {
  129. rules: [{
  130. required: true,
  131. errorMessage: '请选择赛事起始时间',
  132. }]
  133. },
  134. compEndTime: {
  135. rules: [{
  136. required: true,
  137. errorMessage: '请选择赛事截止时间',
  138. },
  139. {
  140. validateFunction: function(rule, value, data, callback) {
  141. if (value <= data.compBeginSecond) {
  142. callback('截止时间必须大于起始时间');
  143. return false;
  144. } else {
  145. return true;
  146. }
  147. }
  148. }
  149. ]
  150. },
  151. description: {
  152. rules: [{
  153. required: true,
  154. errorMessage: '请输入赛事简介',
  155. },
  156. {
  157. minLength: 10,
  158. maxLength: 500,
  159. errorMessage: '赛事简介长度在 {minLength} 到 {maxLength} 个字符',
  160. }
  161. ]
  162. },
  163. rules: {
  164. rules: [{
  165. required: false,
  166. errorMessage: '请输入活动规则',
  167. },
  168. {
  169. minLength: 10,
  170. maxLength: 500,
  171. errorMessage: '活动规则长度在 {minLength} 到 {maxLength} 个字符',
  172. }
  173. ]
  174. },
  175. // matchLogo: {
  176. // rules: [{
  177. // required: true,
  178. // errorMessage: '请选择赛事LOGO',
  179. // }]
  180. // },
  181. mapId: {
  182. rules: [{
  183. required: true,
  184. errorMessage: '请选择赛事场地',
  185. },
  186. {
  187. minimum: 1,
  188. errorMessage: '请选择赛事场地',
  189. }
  190. ]
  191. },
  192. planId: {
  193. rules: [{
  194. required: true,
  195. errorMessage: '请选择赛事方案',
  196. },
  197. {
  198. minimum: 1,
  199. errorMessage: '请选择赛事方案',
  200. }
  201. ]
  202. },
  203. contactName: {
  204. rules: [{
  205. required: true,
  206. errorMessage: '请输入联系人姓名',
  207. },
  208. {
  209. minLength: 2,
  210. maxLength: 20,
  211. errorMessage: '联系人姓名长度在 {minLength} 到 {maxLength} 个字符',
  212. }
  213. ]
  214. },
  215. phone: {
  216. rules: [{
  217. required: true,
  218. errorMessage: '请输入联系人电话',
  219. },
  220. {
  221. pattern: "^((1[3456789][0-9]{1})+\\d{8})$",
  222. errorMessage: '请输入合法的手机号',
  223. }
  224. ]
  225. }
  226. }
  227. }
  228. },
  229. computed: {
  230. ...mapState([
  231. 'username', // 映射 this.username 为 store.state.username
  232. 'token'
  233. ]),
  234. ...mapGetters([
  235. 'metadata'
  236. ]),
  237. },
  238. onLoad(query) {
  239. // console.log(query);
  240. this.queryObj = query;
  241. this.queryString = tools.objectToQueryString(this.queryObj);
  242. // console.log(queryString);
  243. this.from = query["from"] ?? "";
  244. this.compId = query["compId"] ?? 0;
  245. this.compInfoDetail();
  246. this.selectMapQuery();
  247. },
  248. mounted() {},
  249. methods: {
  250. // 自助赛事详情查询
  251. compInfoDetail() {
  252. uni.request({
  253. url: apiCompInfoDetail,
  254. header: this.metadata,
  255. method: "POST",
  256. data: {
  257. compId: this.compId
  258. },
  259. success: (res) => {
  260. // console.log("[compInfoDetail] res", res);
  261. if (checkResCode(res)) {
  262. this.pubState = res.data.data.otherInfo.pubState;
  263. const config = res.data.data.config;
  264. // console.log("[compInfoDetail] config", config);
  265. this.formData.matchLogo = config.tplInfo.matchLogo;
  266. this.formData.matchBanner = config.tplInfo.matchBanner;
  267. this.formData.compName = config.matchInfo.compName;
  268. this.formData.description = config.matchInfo.description;
  269. this.formData.rules = config.matchInfo.rules;
  270. this.formData.contactName = config.matchInfo.contactName;
  271. this.formData.phone = config.matchInfo.phone;
  272. this.formData.regBeginTime = tools.timestampToTime(config.matchInfo.regBeginSecond * 1000);
  273. this.formData.regBeginSecond = config.matchInfo.regBeginSecond;
  274. this.formData.regEndTime = tools.timestampToTime(config.matchInfo.regEndSecond * 1000);
  275. this.formData.regEndSecond = config.matchInfo.regEndSecond;
  276. this.formData.compBeginTime = tools.timestampToTime(config.matchInfo.compBeginSecond * 1000);
  277. this.formData.compBeginSecond = config.matchInfo.compBeginSecond;
  278. this.formData.compEndTime = tools.timestampToTime(config.matchInfo.regEndSecond * 1000);
  279. this.formData.compEndSecond = config.matchInfo.compEndSecond;
  280. this.formData.mapId = config.mapInfo[0].mapId;
  281. this.formData.planId = config.mapInfo[0].planId;
  282. if (config.tplInfo.matchLogo != undefined && config.tplInfo.matchLogo != "") {
  283. this.matchLogoObj = {
  284. // "name": "",
  285. // "extname": "",
  286. "url": config.tplInfo.matchLogo
  287. };
  288. }
  289. this.selectPlanQuery(this.formData.mapId);
  290. }
  291. },
  292. fail: (err) => {
  293. console.log("[compInfoDetail] err", err);
  294. },
  295. });
  296. },
  297. // 自助修改赛事信息
  298. compInfoEdit() {
  299. this.formData.regBeginTime = this.formData.compBeginTime;
  300. this.formData.regEndTime = this.formData.compEndTime;
  301. this.formData.regBeginSecond = Date.parse(this.formData.regBeginTime) / 1000;
  302. this.formData.regEndSecond = Date.parse(this.formData.regEndTime) / 1000;
  303. this.formData.compBeginSecond = Date.parse(this.formData.compBeginTime) / 1000;
  304. this.formData.compEndSecond = Date.parse(this.formData.compEndTime) / 1000;
  305. // console.log("[compInfoEdit] formData:", this.formData);
  306. // console.log("[compInfoEdit] formData:", JSON.stringify(this.formData));
  307. uni.request({
  308. url: apiCompInfoEdit,
  309. header: this.metadata,
  310. method: "POST",
  311. data: {
  312. compId: this.compId,
  313. inJson: JSON.stringify(this.formData)
  314. },
  315. success: (res) => {
  316. console.log("compInfoEdit", res);
  317. if (checkResCode(res)) {
  318. // const data = res.data.data;
  319. uni.showToast({
  320. title: `保存成功`,
  321. icon: 'none',
  322. duration: 3000
  323. });
  324. setTimeout(() => {
  325. this.btnBack();
  326. // this.$router.go(0); // 刷新当前页面
  327. }, 200);
  328. }
  329. },
  330. fail: (err) => {
  331. console.log("compInfoEdit err", err);
  332. },
  333. });
  334. },
  335. // 自助选择公共模板
  336. selectSsctQuery() {
  337. uni.request({
  338. url: apiSelectSsctQuery,
  339. header: this.metadata,
  340. method: "POST",
  341. data: {},
  342. success: (res) => {
  343. // console.log("selectSsctQuery", res);
  344. if (checkResCode(res)) {
  345. // const data = res.data.data;
  346. }
  347. },
  348. fail: (err) => {
  349. console.log("selectSsctQuery err", err);
  350. },
  351. });
  352. },
  353. // 自助选择地图
  354. selectMapQuery() {
  355. uni.request({
  356. url: apiSelectMapQuery,
  357. header: this.metadata,
  358. method: "POST",
  359. data: {},
  360. success: (res) => {
  361. // console.log("selectMapQuery", res);
  362. if (checkResCode(res)) {
  363. const data = res.data.data;
  364. this.mapRs = data;
  365. }
  366. },
  367. fail: (err) => {
  368. console.log("selectMapQuery err", err);
  369. },
  370. });
  371. },
  372. // 自助根据地图选择方案
  373. selectPlanQuery(mapId) {
  374. uni.request({
  375. url: apiSelectPlanQuery,
  376. header: this.metadata,
  377. method: "POST",
  378. data: {
  379. mapId: mapId
  380. },
  381. success: (res) => {
  382. // console.log("selectPlanQuery", res);
  383. if (checkResCode(res)) {
  384. const data = res.data.data;
  385. this.planRs = data;
  386. }
  387. },
  388. fail: (err) => {
  389. console.log("selectPlanQuery err", err);
  390. },
  391. });
  392. },
  393. btnBack() {
  394. if (this.from == "index") {
  395. const url = "/pages/actManage/index";
  396. tools.appAction(url, "uni.switchTab");
  397. } else if (this.from == "actDetail") {
  398. const url = "/pages/actManage/actDetail?compId=" + this.compId;
  399. tools.appAction(url, "uni.navigateTo");
  400. } else {
  401. window.history.back();
  402. }
  403. },
  404. onLogoUploadSelect(e) {
  405. // console.log('[onLogoUploadSelect] 选择文件:', e);
  406. // const imgUrl = e.tempFilePaths[0]; // 获取图片的本地路径
  407. const img = e.tempFiles[0]; // 获取图片信息
  408. // 上传图片
  409. if (img) {
  410. uni.uploadFile({
  411. url: apiUploadFiles, // 你的服务器上传接口地址
  412. filePath: img.path, // 选择的图片路径
  413. name: 'uploadFile', // 必填,后台用来解析的文件名
  414. header: {
  415. // "Content-Type": "multipart/form-data", // H5端不需要添加本句代码
  416. "token": this.token
  417. },
  418. formData: {
  419. // 'user': 'test'
  420. },
  421. success: (uploadFileRes) => {
  422. // console.log("[onLogoUploadSelect] uploadFileRes", uploadFileRes);
  423. // console.log("上传成功", JSON.parse(uploadFileRes.data));
  424. const uploadFileData = JSON.parse(uploadFileRes.data);
  425. if (uploadFileData.code == 0) {
  426. const data = uploadFileData.data;
  427. this.formData.matchLogo = data.url;
  428. this.matchLogoObj = {
  429. "name": img.name,
  430. "extname": img.extname,
  431. "url": data.url
  432. };
  433. } else {
  434. this.formData.matchLogo = "";
  435. this.matchLogoObj = {};
  436. uni.showToast({
  437. title: `图片上传失败 (${uploadFileData.message})`,
  438. icon: 'none',
  439. duration: 5000
  440. });
  441. }
  442. },
  443. fail: (err) => {
  444. console.error("图片上传失败", err);
  445. this.formData.matchLogo = "";
  446. this.matchLogoObj = {};
  447. uni.showToast({
  448. title: `图片上传失败 (${err.errMsg})`,
  449. icon: 'none',
  450. duration: 5000
  451. });
  452. }
  453. });
  454. }
  455. },
  456. onLogoUploadDelete() {
  457. this.formData.matchLogo = "";
  458. },
  459. saveClick() {
  460. // console.log(this.formData);
  461. let that = this;
  462. this.$refs.form.validate().then(res => {
  463. // console.log('表单数据信息:', res);
  464. uni.showModal({
  465. title: '提示',
  466. content: `修改后需要重新进行审核\r\n您确定要继续吗?`,
  467. confirmText: '确定', //确定文本的文字
  468. cancelText: '取消', //确定文本的文字
  469. showCancel: true, //没有取消按钮的弹框
  470. success: function(res) {
  471. if (res.confirm) {
  472. that.compInfoEdit();
  473. } else if (res.cancel) {
  474. }
  475. }
  476. });
  477. }).catch(err => {
  478. console.log('表单错误信息:', err);
  479. uni.showToast({
  480. title: `错误: ${err[0].errorMessage}`,
  481. icon: 'none',
  482. duration: 3000
  483. });
  484. });
  485. },
  486. submitClick() {
  487. },
  488. // 获取 赛事场地 输入框中值
  489. getMapSelectText(data) {
  490. // console.log("getMapSelectText:", data);
  491. // this.coiName = data;
  492. },
  493. // 获取 赛事方案 输入框中值
  494. getPlanSelectText(data) {
  495. // console.log("getPlanSelectText:", data);
  496. // this.coiName = data;
  497. },
  498. // 获取 赛事场地 选择选项值
  499. mapSelectChange(data) {
  500. // console.log("mapSelectChange:", data);
  501. if (data == "clear") { // 用户点击清空图标
  502. this.planRs = [];
  503. }
  504. const mapId = data.Value;
  505. if (mapId > 0) {
  506. this.selectPlanQuery(mapId);
  507. }
  508. },
  509. // 获取 赛事方案 选择选项值
  510. planSelectChange(data) {
  511. // console.log("mapSelectChange:", data);
  512. },
  513. },
  514. }
  515. </script>
  516. <style scoped>
  517. .top {
  518. height: 36px;
  519. flex-shrink: 0;
  520. background: rgb(255, 195, 0, 0.26);
  521. }
  522. .main {}
  523. .form {
  524. width: 90%;
  525. margin-top: 20px;
  526. }
  527. .uni-forms-item {
  528. align-items: center;
  529. margin-bottom: 22px;
  530. }
  531. .input {
  532. width: 90%;
  533. height: 30px;
  534. padding: 0 8px;
  535. border: 1px solid;
  536. border-color: #c6c6c6;
  537. border-radius: 3px;
  538. font-size: 14px;
  539. }
  540. .input-placeholder {
  541. font-weight: 300;
  542. color: #bfbfbf;
  543. font-size: 14px;
  544. }
  545. .button {
  546. width: 36vw;
  547. margin-top: 5px;
  548. margin-bottom: 25px;
  549. border-radius: 6px;
  550. font-weight: 500;
  551. color: #333333;
  552. word-spacing: 15px;
  553. }
  554. .button-save {
  555. color: #ffffff;
  556. background-color: #55aa00;
  557. }
  558. .button-submit {
  559. color: #ffffff;
  560. background-color: #0055ff;
  561. }
  562. </style>