index.vue 16 KB

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