index.vue 14 KB

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