소스 검색

修改赛事报名

zs 8 달 전
부모
커밋
d42e068043

+ 2 - 0
src/lang/package/zh-cn/pages.js

@@ -207,6 +207,8 @@ export default {
   },
   match: {
     addDialogTitle: '新增需赛事',
+    signDialogTitle: '报名管理',
+    scoreDialogTitle: '分数管理',
     upDialogTitle: '修改赛事',
     examDialogTitle: '审核赛事',
     name: '赛事名称',

+ 206 - 0
src/views/information/parts/match/score/index.vue

@@ -0,0 +1,206 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-row justify="center">
+          <el-col :span="16">
+            <el-steps style="max-width: 600px" :active="active" finish-status="success">
+              <el-step v-for="(item, index) in matchPathList" :key="index" :title="item.name" />
+            </el-steps>
+          </el-col>
+        </el-row>
+        <el-col :span="24" class="one">
+          <custom-button-bar :fields="buttonFields" @add="toAdd"></custom-button-bar>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div class="table">
+            <el-table :data="data" border>
+              <el-table-column type="index" label="序号" width="80" align="center" />
+              <el-table-column prop="matchPath_name" label="流程" align="center" />
+              <el-table-column prop="sign_name" label="选手" align="center" />
+              <el-table-column prop="score" label="分数" align="center">
+                <template #default="scope">
+                  <el-input v-model="scope.row.score" type="number" placeholder="请输入分数" />
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" align="center" width="100">
+                <template #default="scope">
+                  <el-link :underline="false" type="primary" size="mini" @click="onSave(scope.row)" style="margin-right: 10px">保存</el-link>
+                  <el-link :underline="false" type="danger" size="mini" @click="onDelete(scope.row)"> 删除 </el-link>
+                </template>
+              </el-table-column>
+            </el-table>
+            <el-col :span="24" class="thr">
+              <el-pagination background layout="prev, pager, next" :total="total" :page-size="limit" v-model:current-page="currentPage" @current-change="changePage" @size-change="sizeChange" />
+            </el-col>
+          </div>
+          <div class="button">
+            <el-button @click="back">上一步</el-button>
+            <el-button @click="next">下一步</el-button>
+          </div>
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose">
+      <el-row>
+        <el-col :span="24" v-if="dialog.type == '1'">
+          <custom-form v-model="form" :fields="formFields" :rules="rules" @save="toSave">
+            <template #matchPath>
+              <el-option v-for="i in matchPathList" disabled :key="i.id" :label="i.name" :value="i.id"></el-option>
+            </template>
+            <template #sign>
+              <el-option v-for="i in signList" :key="i.id" :label="i.name" :value="i.id"></el-option>
+            </template>
+          </custom-form>
+        </el-col>
+      </el-row>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import moment from 'moment'
+import { cloneDeep, get } from 'lodash-es'
+const $checkRes = inject('$checkRes')
+const { t } = useI18n()
+// 接口
+import { ScoreStore } from '@/store/api/platform/score'
+import { SignStore } from '@/store/api/platform/sign'
+import { ProcessStore } from '@/store/api/platform/process'
+const store = ScoreStore()
+const processStore = ProcessStore()
+const signStore = SignStore()
+const props = defineProps({
+  matchInfo: { type: Object }
+})
+const match = computed({
+  get() {
+    return props.matchInfo
+  }
+})
+const id = ref('')
+const data = ref([])
+const searchForm = ref({})
+let skip = 0
+let limit = inject('limit')
+const total = ref(0)
+const currentPage = ref(1)
+const formFields = ref([
+  { label: t('pages.score.matchPath'), model: 'matchPath', type: 'select' },
+  { label: t('pages.score.sign'), model: 'sign', type: 'select' },
+  { label: t('pages.score.score'), model: 'score', type: 'number' }
+])
+const rules = reactive({
+  sign: [{ required: true, message: t('pages.score.signMessage'), trigger: 'blur' }],
+  score: [{ required: true, message: t('pages.score.scoreMessage'), trigger: 'blur' }]
+})
+const dialog = ref({ type: '1', show: false, title: t('pages.score.DialogTitle') })
+const buttonFields = [{ label: t('common.create'), method: 'add' }]
+const form = ref({})
+// 字典表
+const matchPathList = ref([])
+const signList = ref([])
+// 加载中
+const loading = ref(false)
+const searchOther = async () => {
+  let result
+  // 流程
+  result = await processStore.query({ match: id.value, is_use: '0' })
+  if ($checkRes(result)) matchPathList.value = result.data
+  // 选手
+  result = await signStore.query({ match: id.value, status: '1' })
+  if ($checkRes(result)) signList.value = result.data
+}
+const search = async (query = { skip, limit }) => {
+  skip = query.skip
+  limit = query.limit
+  const info = { skip: query.skip, limit: query.limit, ...searchForm.value, match: id.value, matchPath: matchPathList.value[active.value].id }
+  const res = await store.list(info)
+  if (res.errcode == '0') {
+    data.value = res.data
+    total.value = res.total
+  }
+}
+// 添加
+const toAdd = () => {
+  form.value = { matchPath: matchPathList.value[active.value].id }
+  dialog.value = { type: '1', show: true, title: t('pages.score.addDialogTitle') }
+}
+// 删除
+const onDelete = async (data) => {
+  const res = await store.del(data.id)
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+  }
+}
+const onSave = async (data) => {
+  let res
+  const other = { time: moment().format('YYYY-MM-DD'), match: id.value }
+  if (get(data, 'id')) res = await store.update({ ...data, ...other })
+  else res = await store.create({ ...data, ...other })
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+  }
+}
+const toSave = async () => {
+  const data = cloneDeep(form.value)
+  const other = { time: moment().format('YYYY-MM-DD'), match: id.value }
+  let res
+  if (get(data, 'id')) res = await store.update({ ...data, ...other })
+  else res = await store.create({ ...data, ...other })
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+    toClose()
+  }
+}
+const toClose = () => {
+  form.value = {}
+  dialog.value = { show: false }
+}
+const active = ref(0)
+// 上一步
+const back = async () => {
+  if (active.value > 0) active.value = active.value - 1
+  else active.value = 0
+  await search({ skip, limit })
+}
+// 下一步
+const next = async () => {
+  if (active.value < matchPathList.value.length - 1) active.value = active.value + 1
+  else active.value = 0
+  await search({ skip, limit })
+}
+// 分页
+const changePage = (page = currentPage.value) => {
+  search({ skip: (page - 1) * limit, limit: limit })
+}
+const sizeChange = (limits) => {
+  limit = limits
+  currentPage.value = 1
+  search({ skip: 0, limit: limit })
+}
+watch(
+  match,
+  async (item) => {
+    id.value = item.id
+    loading.value = true
+    await searchOther()
+    await search({ skip, limit })
+    loading.value = false
+  },
+  {
+    immediate: true //初始化立即执行
+  }
+)
+</script>
+<style scoped lang="scss">
+.button {
+  text-align: center;
+  margin: 12px 0 0 0;
+}
+.thr {
+  display: flex;
+  justify-content: center;
+  margin: 20px 0 0 0;
+}
+</style>

+ 160 - 0
src/views/information/parts/match/sign/index.vue

@@ -0,0 +1,160 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <custom-search-bar :fields="fields.filter((f) => f.isSearch)" v-model="searchForm" @search="search" @reset="toReset"></custom-search-bar>
+          <custom-table :data="data" :fields="fields" @query="search" :total="total" :opera="opera" @view="toView" @exam="toExam">
+            <template #is_use="{ row }">
+              <el-tag v-if="row.is_use == '0'" type="success" @click="toUse(row, '1')">启用</el-tag>
+              <el-tag v-else type="info" @click="toUse(row, '0')">禁用</el-tag>
+            </template>
+          </custom-table>
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose">
+      <el-row>
+        <el-col :span="24" v-if="dialog.type == '1'">
+          <custom-form v-model="form" :fields="formFields" :useSave="false">
+            <template #cardType>
+              <el-option v-for="i in cardTypeList" :key="i.id" :label="i.label" :value="i.value"></el-option>
+            </template>
+          </custom-form>
+        </el-col>
+        <el-col :span="24" v-if="dialog.type == '2'">
+          <custom-form v-model="examForm" :fields="examFormFields" :rules="examRules" @save="toExamSave">
+            <template #status>
+              <el-option v-for="i in statusList" :key="i.id" :label="i.label" :value="i.value"></el-option>
+            </template>
+          </custom-form>
+        </el-col>
+      </el-row>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { cloneDeep, get } from 'lodash-es'
+const $checkRes = inject('$checkRes')
+const { t } = useI18n()
+// 接口
+import { SignStore } from '@/store/api/platform/sign'
+import { DictDataStore } from '@/store/api/system/dictData'
+const store = SignStore()
+const dictDataStore = DictDataStore()
+
+const data = ref([])
+const searchForm = ref({})
+const fields = [
+  { label: t('pages.sign.name'), model: 'name', isSearch: true },
+  { label: t('pages.sign.phone'), model: 'phone', isSearch: true },
+  { label: t('pages.sign.card'), model: 'card', isSearch: true },
+  { label: t('pages.sign.communication'), model: 'communication' },
+  { label: t('pages.sign.email'), model: 'email' },
+  { label: t('pages.sign.time'), model: 'time' },
+  { label: t('pages.match.status'), model: 'status', format: (i) => getDict(i, 'status') }
+]
+const opera = [
+  { label: t('common.view'), method: 'view' },
+  { label: t('common.exam'), method: 'exam', type: 'warning', display: (i) => i.status === '0' }
+]
+let skip = 0
+let limit = inject('limit')
+const total = ref(0)
+const formFields = ref([
+  { label: t('pages.sign.name'), model: 'name' },
+  { label: t('pages.sign.phone'), model: 'phone' },
+  { label: t('pages.sign.cardType'), model: 'cardType', type: 'select' },
+  { label: t('pages.sign.card'), model: 'card' },
+  { label: t('pages.sign.communication'), model: 'communication' },
+  { label: t('pages.sign.email'), model: 'email' },
+  { label: t('pages.sign.remark'), model: 'remark', type: 'textarea' }
+])
+const dialog = ref({ type: '1', show: false, title: t('pages.sign.DialogTitle') })
+const form = ref({})
+// 审核
+const examFormFields = [{ label: t('pages.match.status'), model: 'status', type: 'select' }]
+const examRules = reactive({
+  status: [{ required: true, message: t('common.statusMessage'), trigger: 'blur' }]
+})
+const examForm = ref({})
+// 字典表
+const cardTypeList = ref([])
+const statusList = ref([])
+// 加载中
+const loading = ref(false)
+const searchOther = async () => {
+  let result
+  // 证件类型
+  result = await dictDataStore.query({ code: 'cardType', is_use: '0' })
+  if ($checkRes(result)) cardTypeList.value = result.data
+  // 状态
+  result = await dictDataStore.query({ code: 'examStatus', is_use: '0' })
+  if ($checkRes(result)) statusList.value = result.data
+}
+const props = defineProps({
+  matchInfo: { type: Object }
+})
+const match = computed({
+  get() {
+    return props.matchInfo
+  }
+})
+const id = ref('')
+const search = async (query = { skip, limit }) => {
+  skip = query.skip
+  limit = query.limit
+  const info = { skip: query.skip, limit: query.limit, ...searchForm.value, match: id.value }
+  const res = await store.query(info)
+  if (res.errcode == '0') {
+    data.value = res.data
+    total.value = res.total
+  }
+}
+// 字典数据转换
+const getDict = (data, model) => {
+  if (data) {
+    let res
+    if (model == 'status') res = statusList.value.find((f) => f.value == data)
+    return get(res, 'label')
+  }
+}
+// 查看
+const toView = async (data) => {
+  form.value = data
+  dialog.value = { type: '1', show: true, title: t('pages.user.dialogTitle') }
+}
+// 审核
+const toExam = (data) => {
+  examForm.value = data
+  dialog.value = { type: '2', show: true, title: t('pages.match.examDialogTitle') }
+}
+// 审核保存
+const toExamSave = async () => {
+  const data = cloneDeep(examForm.value)
+  let res = await store.update({ id: data.id, status: data.status })
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+    toClose()
+  }
+}
+const toClose = () => {
+  examForm.value = {}
+  dialog.value = { show: false }
+}
+watch(
+  match,
+  async (item) => {
+    id.value = item.id
+    loading.value = true
+    await searchOther()
+    await search({ skip, limit })
+    loading.value = false
+  },
+  {
+    immediate: true //初始化立即执行
+  }
+)
+</script>
+<style scoped lang="scss"></style>

+ 23 - 13
src/views/information/parts/platform/match.vue

@@ -142,7 +142,12 @@
             </template>
           </custom-form>
         </el-col>
-        <el-col :span="24" v-if="dialog.type === '3'"> 报名 </el-col>
+        <el-col :span="24" v-if="dialog.type === '3'">
+          <sign :matchInfo="matchInfo"></sign>
+        </el-col>
+        <el-col :span="24" v-if="dialog.type === '4'">
+          <score :matchInfo="matchInfo"></score>
+        </el-col>
       </el-row>
     </el-dialog>
   </div>
@@ -154,8 +159,9 @@ import moment from 'moment'
 import { cloneDeep, get } from 'lodash-es'
 const $checkRes = inject('$checkRes')
 const { t } = useI18n()
-// 路由
-const router = useRouter()
+// 组件
+import sign from '../match/sign/index.vue'
+import score from '../match/score/index.vue'
 // 接口
 import { MatchStore } from '@/store/api/platform/match'
 import { ProcessStore } from '@/store/api/platform/process'
@@ -202,6 +208,7 @@ const buttonFields = [
 let skip = 0
 let limit = inject('limit')
 const total = ref(0)
+const matchInfo = ref({})
 // 字典表
 const isUseList = ref([])
 const statusList = ref([])
@@ -365,15 +372,13 @@ const toEdit = async (data) => {
 }
 // 报名管理
 const toSign = (data) => {
-  router.push({ path: '/match/sign', query: { id: data.id } })
-}
-// 流程管理
-const toProcess = (data) => {
-  router.push({ path: '/match/process', query: { id: data.id } })
+  matchInfo.value = data
+  dialog.value = { type: '3', show: true, title: t('pages.match.signDialogTitle') }
 }
 // 分数管理
 const toScore = (data) => {
-  router.push({ path: '/match/score', query: { id: data.id } })
+  matchInfo.value = data
+  dialog.value = { type: '4', show: true, title: t('pages.match.scoreDialogTitle') }
 }
 // 删除
 const toDelete = async (data) => {
@@ -433,19 +438,24 @@ const toProcessSave = async () => {
     const data = cloneDeep(val)
     delete data.sid
     if (get(data, 'id')) await processStore.update(data)
-    await processStore.create({ ...data, match: form.value.id })
+    else await processStore.create(data)
   }
 }
 // 流程添加
 const addProcess = () => {
   let list = processList.value || []
-  list.push({ sid: moment().valueOf(), name: '', time: '', is_use: '' })
+  list.push({ sid: moment().valueOf(), name: '', time: '', is_use: '', match: form.value.id })
   processList.value = list
 }
 // 流程删除
 const delProcess = async (e) => {
-  let list = processList.value.filter((i) => i.sid != e.sid)
-  processList.value = list
+  if (e.sid) {
+    let list = processList.value.filter((i) => i.sid != e.sid)
+    processList.value = list
+  } else {
+    let list = processList.value.filter((i) => i.id != e.id)
+    processList.value = list
+  }
   if (e.id) await processStore.del(e.id)
 }
 // 重置