Pārlūkot izejas kodu

修改分数跟流程

zs 8 mēneši atpakaļ
vecāks
revīzija
4c535dfc59

+ 40 - 0
src/store/api/platform/process.js

@@ -0,0 +1,40 @@
+import { defineStore } from 'pinia'
+import { AxiosWrapper } from '@/utils/axios-wrapper'
+import { get } from 'lodash-es'
+const url = '/matchPath'
+const axios = new AxiosWrapper()
+
+export const ProcessStore = defineStore('process', () => {
+  const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
+    let cond = {}
+    if (skip) cond.skip = skip
+    if (limit) cond.limit = limit
+    cond = { ...cond, ...info }
+    const res = await axios.$get(`${url}`, cond)
+    return res
+  }
+  const fetch = async (payload) => {
+    const res = await axios.$get(`${url}/${payload}`)
+    return res
+  }
+  const create = async (payload) => {
+    const res = await axios.$post(`${url}`, payload)
+    return res
+  }
+  const update = async (payload) => {
+    const id = get(payload, 'id', get(payload, 'id'))
+    const res = await axios.$post(`${url}/${id}`, payload)
+    return res
+  }
+  const del = async (payload) => {
+    const res = await axios.$delete(`${url}/${payload}`)
+    return res
+  }
+  return {
+    query,
+    fetch,
+    create,
+    update,
+    del
+  }
+})

+ 54 - 0
src/store/api/platform/score.js

@@ -0,0 +1,54 @@
+import { defineStore } from 'pinia'
+import { AxiosWrapper } from '@/utils/axios-wrapper'
+import { get } from 'lodash-es'
+const url = '/score'
+const axios = new AxiosWrapper()
+
+export const ScoreStore = defineStore('score', () => {
+  const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
+    let cond = {}
+    if (skip) cond.skip = skip
+    if (limit) cond.limit = limit
+    cond = { ...cond, ...info }
+    const res = await axios.$get(`${url}`, cond)
+    return res
+  }
+  const list = async ({ skip = 0, limit = undefined, ...info } = {}) => {
+    let cond = {}
+    if (skip) cond.skip = skip
+    if (limit) cond.limit = limit
+    cond = { ...cond, ...info }
+    const res = await axios.$get(`${url}/list`, cond)
+    return res
+  }
+  const fetch = async (payload) => {
+    const res = await axios.$get(`${url}/${payload}`)
+    return res
+  }
+  const detail = async (payload) => {
+    const res = await axios.$get(`${url}/detail/${payload}`)
+    return res
+  }
+  const create = async (payload) => {
+    const res = await axios.$post(`${url}`, payload)
+    return res
+  }
+  const update = async (payload) => {
+    const id = get(payload, 'id', get(payload, '_id'))
+    const res = await axios.$post(`${url}/${id}`, payload)
+    return res
+  }
+  const del = async (payload) => {
+    const res = await axios.$delete(`${url}/${payload}`)
+    return res
+  }
+  return {
+    query,
+    list,
+    fetch,
+    detail,
+    create,
+    update,
+    del
+  }
+})

+ 6 - 0
src/views/center/attestation.vue

@@ -77,6 +77,8 @@ const IndustryList = ref([])
 const cardTypeList = ref([])
 const contributionList = ref([])
 const plateList = ref([])
+const modeList = ref([])
+
 // 请求
 onMounted(async () => {
   loading.value = true
@@ -128,6 +130,9 @@ const searchOther = async () => {
   // 板块
   result = await sectorStore.query({ is_use: '0' })
   if ($checkRes(result)) plateList.value = result.data
+  // 盈利模式
+  result = await dictDataStore.query({ code: 'modeType', is_use: '0' })
+  if ($checkRes(result)) modeList.value = result.data
 }
 const search = async () => {
   if (user.value.id) {
@@ -150,6 +155,7 @@ provide('IndustryList', IndustryList)
 provide('cardTypeList', cardTypeList)
 provide('contributionList', contributionList)
 provide('plateList', plateList)
+provide('modeList', modeList)
 </script>
 <style scoped lang="scss">
 .main {

+ 34 - 3
src/views/center/match.vue

@@ -31,7 +31,9 @@
             <el-table-column align="center" label="操作" width="250">
               <template #default="{ row }">
                 <el-link v-if="row.status == '-2'" :underline="false" type="warning" size="mini" @click="toExam(row)" style="margin-right: 10px">提交审核</el-link>
+                <el-link v-if="row.match_status == '2'" :underline="false" type="primary" size="mini" @click="toScore(row)" style="margin-right: 10px">分数</el-link>
                 <el-link :underline="false" type="warning" size="mini" @click="toSign(row)" style="margin-right: 10px">报名</el-link>
+                <el-link v-if="row.scale == '0'" :underline="false" type="warning" size="mini" @click="toProcess(row)" style="margin-right: 10px">流程</el-link>
                 <el-link :underline="false" type="primary" size="mini" @click="toEdit(row)" style="margin-right: 10px">修改</el-link>
                 <el-link :underline="false" type="danger" size="mini" @click="toDelete(row)"> 删除 </el-link>
               </template>
@@ -47,6 +49,9 @@
       <el-row>
         <el-col :span="24" v-if="dialog.type == '1'">
           <custom-form v-model="form" :fields="formFields" :rules="rules" @save="toSave" @draftSave="toDraftSave">
+            <template #video>
+              <custom-upload model="video" :list="form.video" :limit="1" url="/files/web/cxyy_match/upload" @change="onUpload"></custom-upload>
+            </template>
             <template #file>
               <custom-upload model="file" :list="form.file" :limit="1" listType="picture-card" url="/files/web/cxyy_match/upload" @change="onUpload"></custom-upload>
             </template>
@@ -59,6 +64,9 @@
             <template #match_status>
               <el-option v-for="i in matchList" :key="i.id" :label="i.label" :value="i.value"></el-option>
             </template>
+            <template #scale>
+              <el-radio v-for="i in scaleList" :key="i.id" :label="i.value">{{ i.label }}</el-radio>
+            </template>
             <template #match_type>
               <el-radio v-for="i in matchTypeList" :key="i.id" :label="i.value">{{ i.label }}</el-radio>
             </template>
@@ -123,6 +131,12 @@
         <el-col :span="24" v-if="dialog.type == '2'">
           <sign :matchForm="form"></sign>
         </el-col>
+        <el-col :span="24" v-if="dialog.type == '3'">
+          <process :matchForm="form"></process>
+        </el-col>
+        <el-col :span="24" v-if="dialog.type == '4'">
+          <score :matchForm="form"></score>
+        </el-col>
       </el-row>
     </el-dialog>
   </div>
@@ -131,7 +145,8 @@
 <script setup>
 // 组件
 import sign from './parts/sign.vue'
-
+import process from './parts/process.vue'
+import score from './parts/score.vue'
 import { Search } from '@element-plus/icons-vue'
 import { cloneDeep, get } from 'lodash-es'
 const $checkRes = inject('$checkRes')
@@ -166,6 +181,7 @@ const formList = ref([])
 const tagsList = ref([])
 const sectorList = ref([])
 const matchTypeList = ref([])
+const scaleList = ref([])
 
 const form = ref({ time: [], rules: {} })
 const dialog = ref({ type: '1', show: false, title: '发布赛事' })
@@ -174,8 +190,9 @@ const formFields = ref([
   { label: '赛事名称', model: 'name' },
   { label: '标签', model: 'tags', custom: true },
   { label: '类型', model: 'type', type: 'select' },
+  { label: '赛事规模', model: 'scale', type: 'radio' },
   { label: '赛事类型', model: 'match_type', type: 'radio' },
-  { label: '路由', model: 'href' },
+  { label: '路由', model: 'href', display: () => form.value.match_type == '1' },
   { label: '组织单位', model: 'work' },
   { label: '所属产业', model: 'industry', type: 'select' },
   { label: '类别', model: 'form', type: 'select' },
@@ -184,6 +201,7 @@ const formFields = ref([
   { label: '是否启用', model: 'is_use', type: 'radio' },
   { model: 'rules', custom: true },
   { label: '简介', model: 'brief', custom: true },
+  { label: '视频', model: 'video', custom: true },
   { label: '赛事状态', model: 'match_status', type: 'select' }
 ])
 const rules = reactive({ name: [{ required: true, message: '请输入赛事名称', trigger: 'blur' }] })
@@ -244,6 +262,9 @@ const searchOther = async () => {
   // 赛事状态
   result = await dictDataStore.query({ code: 'matchStatus', is_use: '0' })
   if ($checkRes(result)) matchList.value = result.data
+  // 赛事规模
+  result = await dictDataStore.query({ code: 'matchScale', is_use: '0' })
+  if ($checkRes(result)) scaleList.value = result.data
   // 标签
   result = await tagsStore.query({ is_use: '0' })
   if ($checkRes(result)) tagsList.value = result.data
@@ -274,6 +295,16 @@ const toSign = (data) => {
   form.value = data
   dialog.value = { type: '2', show: true, title: '报名管理' }
 }
+// 流程
+const toProcess = (data) => {
+  form.value = data
+  dialog.value = { type: '3', show: true, title: '流程管理' }
+}
+// 分数管理
+const toScore = (data) => {
+  form.value = data
+  dialog.value = { type: '4', show: true, title: '分数管理' }
+}
 // 删除
 const toDelete = (data) => {
   ElMessageBox.confirm(`您确认删除${data.name}该数据?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
@@ -287,7 +318,7 @@ const toDelete = (data) => {
 }
 const toSave = async () => {
   const data = cloneDeep(form.value)
-  const other = { status: '0', user: user.value.id }
+  const other = { status: '0', user: user.value.id, form: searchForm.value.form }
   if (data.time && data.time.length > 1) {
     data.start_time = data.time[0]
     data.end_time = data.time[1]

+ 9 - 0
src/views/center/parts/competition.vue

@@ -27,6 +27,13 @@
           </el-form-item>
         </el-col>
       </el-row>
+      <el-col :span="24">
+        <el-form-item label="盈利模式" prop="mode">
+          <el-radio-group size="large" v-model="form.mode">
+            <el-radio v-for="i in modeList" :key="i._id" :label="i.value">{{ i.label }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-col>
       <el-col :span="24">
         <el-form-item label="地址" prop="address">
           <el-input size="large" v-model="form.address" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" placeholder="请输入地址" />
@@ -55,6 +62,8 @@ const user = computed(() => userStore.user)
 const ruleFormRef = ref()
 // 字典表
 const isUseList = inject('isUseList')
+const modeList = inject('modeList')
+
 // 接口
 import { CompetitionStore } from '@/store/api/user/competition'
 const competitionStore = CompetitionStore()

+ 193 - 0
src/views/center/parts/process.vue

@@ -0,0 +1,193 @@
+<template>
+  <div class="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <div class="one_left" @click="toAdd">发布流程</div>
+          <div class="one_right">
+            <el-input v-model="searchForm.name" style="width: 250px" size="large" placeholder="搜索" @change="search" :suffix-icon="Search" />
+          </div>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-table :data="list" style="width: 100%" size="large" :header-cell-style="{ backgroundColor: '#edf3ff' }">
+            <template #empty>
+              <el-empty description="暂无数据" />
+            </template>
+            <el-table-column prop="name" align="center" label="流程名称" />
+            <el-table-column prop="time" align="center" label="时间" width="180" />
+            <el-table-column prop="order_num" align="center" label="排序" width="180" />
+            <el-table-column prop="is_use" align="center" label="是否启用" width="180">
+              <template #default="scope">
+                <div>{{ getDict(scope.row.is_use, 'is_use') }}</div>
+              </template>
+            </el-table-column>
+            <el-table-column align="center" label="操作" width="180">
+              <template #default="{ row }">
+                <el-link :underline="false" type="primary" size="mini" @click="toEdit(row)" style="margin-right: 10px">修改</el-link>
+                <el-link :underline="false" type="danger" size="mini" @click="toDelete(row)"> 删除 </el-link>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-col>
+        <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>
+      </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" :DraftSave="false" submitText="保存">
+            <template #is_use>
+              <el-radio v-for="i in isUseList" :key="i.id" :label="i.value">{{ i.label }}</el-radio>
+            </template>
+            <template #brief>
+              <WangEditor v-model="form.brief" />
+            </template>
+          </custom-form>
+        </el-col>
+      </el-row>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { Search } from '@element-plus/icons-vue'
+import { cloneDeep, get } from 'lodash-es'
+const $checkRes = inject('$checkRes')
+// 接口
+import { ProcessStore } from '@/store/api/platform/process'
+import { DictDataStore } from '@/store/api/system/dictData'
+const store = ProcessStore()
+const dictDataStore = DictDataStore()
+// 加载中
+const loading = ref(false)
+
+const searchForm = ref({})
+// 列表
+const list = ref([])
+let skip = 0
+let limit = inject('limit')
+const total = ref(0)
+const currentPage = ref(1)
+
+const props = defineProps({
+  matchForm: { type: Object, default: () => {} }
+})
+
+const { matchForm } = toRefs(props)
+
+// 字典表
+const isUseList = ref([])
+
+const form = ref({})
+const dialog = ref({ type: '1', show: false, title: '发布流程' })
+const formFields = ref([
+  { label: '名称', model: 'name' },
+  { label: '时间', model: 'time', type: 'date' },
+  { label: '排序', model: 'order_num', type: 'number' },
+  { label: '简介', model: 'brief', custom: true },
+  { label: '是否启用', model: 'is_use', type: 'radio' }
+])
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  await search()
+  loading.value = false
+})
+const search = async (query = { skip, limit }) => {
+  skip = query.skip
+  limit = query.limit
+  const info = {
+    skip: query.skip,
+    limit: query.limit,
+    match: matchForm.value.id,
+    ...searchForm.value
+  }
+  const res = await store.query(info)
+  if (res.errcode == '0') {
+    list.value = res.data
+    total.value = res.total
+  }
+}
+const searchOther = async () => {
+  let result
+  // 是否使用
+  result = await dictDataStore.query({ code: 'isUse', is_use: '0' })
+  if ($checkRes(result)) isUseList.value = result.data
+}
+// 字典数据转换
+const getDict = (data, model) => {
+  if (data) {
+    let res
+    if (model == 'is_use') res = isUseList.value.find((f) => f.value == data)
+    return get(res, 'label')
+  }
+}
+// 添加
+const toAdd = () => {
+  dialog.value = { type: '1', show: true, title: '添加流程' }
+}
+// 修改
+const toEdit = (data) => {
+  form.value = data
+  dialog.value = { type: '1', show: true, title: '修改流程' }
+}
+// 删除
+const toDelete = async (data) => {
+  const res = await store.del(data.id)
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+  }
+}
+const toSave = async () => {
+  const data = cloneDeep(form.value)
+  let res
+  if (get(data, 'id')) res = await store.update(data)
+  else res = await store.create({ ...data, match: matchForm.value.id })
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+    toClose()
+  }
+}
+const toClose = () => {
+  form.value = {}
+  dialog.value = { show: false }
+}
+// 分页
+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 })
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .one {
+    height: 50px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin: 0 0 10px 0;
+    .one_left {
+      background: #1875df;
+      padding: 0 10px;
+      height: 30px;
+      color: #fff;
+      line-height: 30px;
+      text-align: center;
+      font-size: 16px;
+      cursor: default;
+    }
+  }
+  .thr {
+    display: flex;
+    justify-content: center;
+    margin: 20px 0 0 0;
+  }
+}
+</style>

+ 185 - 0
src/views/center/parts/score.vue

@@ -0,0 +1,185 @@
+<template>
+  <div class="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <div class="one_left" @click="toAdd">添加分数</div>
+          <div class="one_right">
+            <el-input v-model="searchForm.matchPath_name" style="width: 250px" size="large" placeholder="搜索" @change="search" :suffix-icon="Search" />
+          </div>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-table :data="list" style="width: 100%" size="large" :header-cell-style="{ backgroundColor: '#edf3ff' }">
+            <template #empty>
+              <el-empty description="暂无数据" />
+            </template>
+            <el-table-column prop="matchPath_name" align="center" label="流程名称" />
+            <el-table-column prop="sign_name" align="center" label="选手" />
+            <el-table-column prop="score" align="center" label="分数" width="180" />
+            <el-table-column prop="time" align="center" label="时间" width="180" />
+            <el-table-column align="center" label="操作" width="180">
+              <template #default="{ row }">
+                <el-link :underline="false" type="primary" size="mini" @click="toEdit(row)" style="margin-right: 10px">修改</el-link>
+                <el-link :underline="false" type="danger" size="mini" @click="toDelete(row)"> 删除 </el-link>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-col>
+        <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>
+      </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" :DraftSave="false" submitText="保存">
+            <template #matchPath>
+              <el-option v-for="i in matchPathList" :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')
+// 接口
+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 searchForm = ref({})
+
+// 列表
+const list = ref([])
+let skip = 0
+let limit = inject('limit')
+const total = ref(0)
+const currentPage = ref(1)
+
+const props = defineProps({
+  matchForm: { type: Object, default: () => {} }
+})
+
+const { matchForm } = toRefs(props)
+
+const formFields = ref([
+  { label: '流程', model: 'matchPath', type: 'select' },
+  { label: '选手', model: 'sign', type: 'select' },
+  { label: '分数', model: 'score', type: 'number' }
+])
+const rules = reactive({
+  sign: [{ required: true, message: '请选择选手', trigger: 'blur' }],
+  score: [{ required: true, message: '请填写分数', trigger: 'blur' }]
+})
+const dialog = ref({ type: '1', show: false, title: '维护分数' })
+const form = ref({})
+// 字典表
+const matchPathList = ref([])
+const signList = ref([])
+// 加载中
+const loading = ref(false)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  await search({ skip, limit })
+  loading.value = false
+})
+const searchOther = async () => {
+  let result
+  // 流程
+  result = await processStore.query({ match: matchForm.value.id, is_use: '0' })
+  if ($checkRes(result)) matchPathList.value = result.data
+  // 选手
+  result = await signStore.query({ match: matchForm.value.id, 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: matchForm.value.id }
+  const res = await store.list(info)
+  if (res.errcode == '0') {
+    list.value = res.data
+    total.value = res.total
+  }
+}
+// 添加
+const toAdd = () => {
+  dialog.value = { type: '1', show: true, title: '添加分数' }
+}
+// 修改
+const toEdit = (data) => {
+  form.value = data
+  dialog.value = { type: '1', show: true, title: '修改分数' }
+}
+// 删除
+const toDelete = async (data) => {
+  const res = await store.del(data.id)
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+  }
+}
+const toSave = async () => {
+  const data = cloneDeep(form.value)
+  const other = { time: moment().format('YYYY-MM-DD'), match: matchForm.value.id }
+  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 changePage = (page = currentPage.value) => {
+  search({ skip: (page - 1) * limit, limit: limit })
+}
+const sizeChange = (limits) => {
+  limit = limits
+  currentPage.value = 1
+  search({ skip: 0, limit: limit })
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .one {
+    height: 50px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin: 0 0 10px 0;
+    .one_left {
+      background: #1875df;
+      padding: 0 10px;
+      height: 30px;
+      color: #fff;
+      line-height: 30px;
+      text-align: center;
+      font-size: 16px;
+      cursor: default;
+    }
+  }
+  .thr {
+    display: flex;
+    justify-content: center;
+    margin: 20px 0 0 0;
+  }
+}
+</style>

+ 1 - 1
src/views/center/parts/sign.vue

@@ -88,7 +88,7 @@ const cardTypeList = ref([])
 const statusList = ref([])
 
 const form = ref({})
-const dialog = ref({ type: '1', show: false, title: '发布需求' })
+const dialog = ref({ type: '1', show: false, title: '报名管理' })
 const formFields = ref([
   { label: '姓名', model: 'name' },
   { label: '手机号', model: 'phone' },