|
@@ -5,30 +5,96 @@
|
|
|
<userCard />
|
|
<userCard />
|
|
|
|
|
|
|
|
<a-card title="账号列表" style="margin-top: 15px;">
|
|
<a-card title="账号列表" style="margin-top: 15px;">
|
|
|
- <a-button type="primary" size="large" @click="editAccount()">
|
|
|
|
|
- <template #icon>
|
|
|
|
|
- <icon-plus />
|
|
|
|
|
- </template>
|
|
|
|
|
- 添加账号
|
|
|
|
|
- </a-button>
|
|
|
|
|
-
|
|
|
|
|
- <a-button size="large" @click="download" style="margin-left: 10px;">
|
|
|
|
|
- <template #icon>
|
|
|
|
|
- <icon-question-circle />
|
|
|
|
|
- </template>
|
|
|
|
|
- 操作说明
|
|
|
|
|
- </a-button>
|
|
|
|
|
-
|
|
|
|
|
- <a-button size="large" @click="$router.push('/download/down')" style="margin-left: 10px;" v-if="!isElectron()">
|
|
|
|
|
- <template #icon>
|
|
|
|
|
- <icon-download />
|
|
|
|
|
- </template>
|
|
|
|
|
- 客户端/登录器下载
|
|
|
|
|
- </a-button>
|
|
|
|
|
|
|
+ <div class="buttonGroup">
|
|
|
|
|
+ <a-button type="primary" size="large" @click="editAccount()">
|
|
|
|
|
+ <template #icon>
|
|
|
|
|
+ <icon-plus />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ 添加账号
|
|
|
|
|
+ </a-button>
|
|
|
|
|
+
|
|
|
|
|
+ <a-button size="large" @click="download" style="margin-left: 10px;">
|
|
|
|
|
+ <template #icon>
|
|
|
|
|
+ <icon-question-circle />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ 操作说明
|
|
|
|
|
+ </a-button>
|
|
|
|
|
+
|
|
|
|
|
+ <a-button size="large" @click="$router.push('/download/down')" style="margin-left: 10px;" v-if="!isElectron()">
|
|
|
|
|
+ <template #icon>
|
|
|
|
|
+ <icon-download />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ 客户端/登录器下载
|
|
|
|
|
+ </a-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <a-row class="queryForm">
|
|
|
|
|
+ <a-col :flex="1">
|
|
|
|
|
+ <a-form :model="queryData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
|
|
|
|
|
+ label-align="left">
|
|
|
|
|
+ <a-row :gutter="16">
|
|
|
|
|
+ <a-col :span="8">
|
|
|
|
|
+ <a-form-item field="area" label="跑区">
|
|
|
|
|
+ <a-select v-model="queryData.area" placeholder="请选择乐跑跑区" default-value="">
|
|
|
|
|
+ <a-option value="">所有</a-option>
|
|
|
|
|
+ <a-option v-for="(item, index) in area" :key="index" :value="item">
|
|
|
|
|
+ {{ item }}
|
|
|
|
|
+ </a-option>
|
|
|
|
|
+ </a-select>
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+ </a-col>
|
|
|
|
|
+ <a-col :span="8">
|
|
|
|
|
+ <a-form-item field="email" label="用户邮箱">
|
|
|
|
|
+ <a-input v-model="queryData.email" allow-clear/>
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+ </a-col>
|
|
|
|
|
+ <a-col :span="8">
|
|
|
|
|
+ <a-form-item field="username" label="账号名称">
|
|
|
|
|
+ <a-input v-model="queryData.username" allow-clear/>
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+ </a-col>
|
|
|
|
|
+ <a-col :span="8">
|
|
|
|
|
+ <a-form-item field="student_num" label="学号">
|
|
|
|
|
+ <a-input v-model="queryData.student_num" allow-clear/>
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+ </a-col>
|
|
|
|
|
+ <a-col :span="8">
|
|
|
|
|
+ <a-form-item field="area" label="账号状态">
|
|
|
|
|
+ <a-select v-model="queryData.state" :options="state" placeholder="请选择账号状态" :default-value="-1" />
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+ </a-col>
|
|
|
|
|
+ </a-row>
|
|
|
|
|
+ </a-form>
|
|
|
|
|
+ </a-col>
|
|
|
|
|
+ <a-divider style="height: 84px" direction="vertical" />
|
|
|
|
|
+ <a-col :flex="'86px'" style="text-align: right">
|
|
|
|
|
+ <a-space direction="vertical" :size="18">
|
|
|
|
|
+ <a-button type="primary" @click="search">
|
|
|
|
|
+ <template #icon>
|
|
|
|
|
+ <icon-search />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ 搜索
|
|
|
|
|
+ </a-button>
|
|
|
|
|
+ <a-button @click="reset">
|
|
|
|
|
+ <template #icon>
|
|
|
|
|
+ <icon-refresh />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ 重置
|
|
|
|
|
+ </a-button>
|
|
|
|
|
+ </a-space>
|
|
|
|
|
+ </a-col>
|
|
|
|
|
+ </a-row>
|
|
|
|
|
|
|
|
<a-table :data="data" stripe hoverable column-resizable class="table" :loading="loading" :scroll="{
|
|
<a-table :data="data" stripe hoverable column-resizable class="table" :loading="loading" :scroll="{
|
|
|
x: 1600
|
|
x: 1600
|
|
|
- }" :pagination="{ showPageSize: true, showJumper: true, defaultPageSize: 15 }">
|
|
|
|
|
|
|
+ }" :pagination="{
|
|
|
|
|
+ showPageSize: true,
|
|
|
|
|
+ showJumper: true,
|
|
|
|
|
+ showTotal: true,
|
|
|
|
|
+ pageSize: pagination.pagesize,
|
|
|
|
|
+ current: pagination.current,
|
|
|
|
|
+ total: pagination.total
|
|
|
|
|
+ }" @page-change="handlePageChange" @page-size-change="handlePageSizeChange">
|
|
|
|
|
|
|
|
<template #name-filter="{ filterValue, setFilterValue, handleFilterConfirm, handleFilterReset }">
|
|
<template #name-filter="{ filterValue, setFilterValue, handleFilterConfirm, handleFilterReset }">
|
|
|
<div class="custom-filter">
|
|
<div class="custom-filter">
|
|
@@ -154,7 +220,7 @@
|
|
|
</a-table-column>
|
|
</a-table-column>
|
|
|
<a-table-column title="上次登录时间" :width="170" ellipsis tooltip>
|
|
<a-table-column title="上次登录时间" :width="170" ellipsis tooltip>
|
|
|
<template #cell="{ record }">
|
|
<template #cell="{ record }">
|
|
|
- {{ record.update_time ? stramptoTime(record.update_time) : '待登录' }}
|
|
|
|
|
|
|
+ {{ record.update_time ? stramptoTime(record.update_time) : '待登录' }}
|
|
|
</template>
|
|
</template>
|
|
|
</a-table-column>
|
|
</a-table-column>
|
|
|
<a-table-column title="备注" :width="200" ellipsis tooltip>
|
|
<a-table-column title="备注" :width="200" ellipsis tooltip>
|
|
@@ -187,10 +253,11 @@
|
|
|
:ok-loading="ok_loading" esc-to-close closable>
|
|
:ok-loading="ok_loading" esc-to-close closable>
|
|
|
<a-form :model="form">
|
|
<a-form :model="form">
|
|
|
<a-form-item field="student_num" label="学号">
|
|
<a-form-item field="student_num" label="学号">
|
|
|
- <a-input v-model="form.student_num" placeholder="账号所有者学号,填写错误将无法登录" allow-clear/>
|
|
|
|
|
|
|
+ <a-input v-model="form.student_num" placeholder="账号所有者学号,填写错误将无法登录" allow-clear />
|
|
|
</a-form-item>
|
|
</a-form-item>
|
|
|
<a-form-item field="email" label="通知邮箱">
|
|
<a-form-item field="email" label="通知邮箱">
|
|
|
- <a-auto-complete :data="email" @search="handleSearch" v-model="form.email" placeholder="用于接收乐跑失败、登录失效的通知" allow-clear/>
|
|
|
|
|
|
|
+ <a-auto-complete :data="email" @search="handleSearch" v-model="form.email" placeholder="用于接收乐跑失败、登录失效的通知"
|
|
|
|
|
+ allow-clear />
|
|
|
</a-form-item>
|
|
</a-form-item>
|
|
|
<a-form-item field="area" label="乐跑跑区">
|
|
<a-form-item field="area" label="乐跑跑区">
|
|
|
<a-select v-model="form.area" placeholder="请选择乐跑跑区" default-value="">
|
|
<a-select v-model="form.area" placeholder="请选择乐跑跑区" default-value="">
|
|
@@ -213,17 +280,6 @@
|
|
|
<a-textarea v-model="form.notes" placeholder="添加对账号的备注(非必填)" :max-length="{ length: 50 }" allow-clear
|
|
<a-textarea v-model="form.notes" placeholder="添加对账号的备注(非必填)" :max-length="{ length: 50 }" allow-clear
|
|
|
show-word-limit />
|
|
show-word-limit />
|
|
|
</a-form-item>
|
|
</a-form-item>
|
|
|
- <!-- <a-form-item field="distance" label="距离区间">
|
|
|
|
|
- <a-select v-model="form.distance" placeholder="请选择距离区间">
|
|
|
|
|
- <a-option :value="0">默认(2~4Km)</a-option>
|
|
|
|
|
- <a-option v-for="(item, index) in distance" :key="index" :value="item.value">
|
|
|
|
|
- <div class="vipcontent">
|
|
|
|
|
- <div>{{ item.label }} </div>
|
|
|
|
|
- <img src="@/assets/vip.svg" alt="vip" height="20">
|
|
|
|
|
- </div>
|
|
|
|
|
- </a-option>
|
|
|
|
|
- </a-select>
|
|
|
|
|
- </a-form-item> -->
|
|
|
|
|
</a-form>
|
|
</a-form>
|
|
|
</a-modal>
|
|
</a-modal>
|
|
|
</template>
|
|
</template>
|
|
@@ -237,6 +293,21 @@ import userCard from '@/components/userCard/userCard.vue'
|
|
|
import { isElectron } from '@/utils/electron'
|
|
import { isElectron } from '@/utils/electron'
|
|
|
|
|
|
|
|
const email = ref([])
|
|
const email = ref([])
|
|
|
|
|
+
|
|
|
|
|
+const queryData = reactive({
|
|
|
|
|
+ area: '',
|
|
|
|
|
+ student_num: '',
|
|
|
|
|
+ email: '',
|
|
|
|
|
+ username: '',
|
|
|
|
|
+ state: -1
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const pagination = reactive({
|
|
|
|
|
+ total: 0,
|
|
|
|
|
+ current: 1, // 默认从第1页开始
|
|
|
|
|
+ pagesize: 20
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
const handleSearch = (value) => {
|
|
const handleSearch = (value) => {
|
|
|
const emailSuffix = ["qq.com", "ctbu.edu.cn"]
|
|
const emailSuffix = ["qq.com", "ctbu.edu.cn"]
|
|
|
const input = (value || "").trim()
|
|
const input = (value || "").trim()
|
|
@@ -266,10 +337,36 @@ const handleSearch = (value) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const area = ["兰花湖校区跑区", "主校区北跑区", "主校区南跑区", "重庆工商大学茶园校区"]
|
|
const area = ["兰花湖校区跑区", "主校区北跑区", "主校区南跑区", "重庆工商大学茶园校区"]
|
|
|
-const distance = [
|
|
|
|
|
- { label: '女生(1.6~2Km)', value: [1.60, 2.00] },
|
|
|
|
|
- { label: '男生(2.0~2.4Km)', value: [2.00, 2.40] }
|
|
|
|
|
|
|
+const state = [
|
|
|
|
|
+ { label: '全部', value: -1 }, { label: '需登录', value: 0 }, { label: '正常', value: 1 }, { label: '状态异常', value: 2 }
|
|
|
]
|
|
]
|
|
|
|
|
+
|
|
|
|
|
+const search = () => {
|
|
|
|
|
+ pagination.current = 1
|
|
|
|
|
+ getAccountsAsync()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const reset = () => {
|
|
|
|
|
+ queryData.area = ''
|
|
|
|
|
+ queryData.student_num = ''
|
|
|
|
|
+ queryData.email = ''
|
|
|
|
|
+ queryData.username = ''
|
|
|
|
|
+ getAccountsAsync()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 分页 - 页码变化
|
|
|
|
|
+const handlePageChange = (page) => {
|
|
|
|
|
+ pagination.current = page
|
|
|
|
|
+ getAccountsAsync()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 分页 - 每页条数变化
|
|
|
|
|
+const handlePageSizeChange = (size) => {
|
|
|
|
|
+ pagination.pagesize = size
|
|
|
|
|
+ pagination.current = 1 // 页大小变化后回到第一页
|
|
|
|
|
+ getAccountsAsync()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
const auto_time = Array.from({ length: 17 }, (_, i) => {
|
|
const auto_time = Array.from({ length: 17 }, (_, i) => {
|
|
|
const hour = i + 7
|
|
const hour = i + 7
|
|
|
return {
|
|
return {
|
|
@@ -383,18 +480,31 @@ const handleCancel = () => {
|
|
|
visible.value = false
|
|
visible.value = false
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const getAccountsAsync = async () => {
|
|
|
|
|
+ loading.value = true
|
|
|
|
|
+ await getAccounts()
|
|
|
|
|
+ loading.value = false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
const getAccounts = async () => {
|
|
const getAccounts = async () => {
|
|
|
try {
|
|
try {
|
|
|
- const res = await accountList()
|
|
|
|
|
|
|
+ const reqData = {
|
|
|
|
|
+ ...queryData,
|
|
|
|
|
+ pagesize: pagination.pagesize,
|
|
|
|
|
+ current: pagination.current
|
|
|
|
|
+ }
|
|
|
|
|
+ const res = await accountList(reqData)
|
|
|
if (!res || res.code !== 0)
|
|
if (!res || res.code !== 0)
|
|
|
return Notification.error({
|
|
return Notification.error({
|
|
|
- title: '获取账号列表失败!',
|
|
|
|
|
|
|
+ title: '获取路径数据失败!',
|
|
|
content: res?.msg ?? '请稍后再试'
|
|
content: res?.msg ?? '请稍后再试'
|
|
|
})
|
|
})
|
|
|
|
|
+
|
|
|
data.value = res.data
|
|
data.value = res.data
|
|
|
|
|
+ pagination.total = res.pagination.total
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
Notification.error({
|
|
Notification.error({
|
|
|
- title: '获取账号列表失败!',
|
|
|
|
|
|
|
+ title: '获取路径数据失败!',
|
|
|
content: error.message || '请稍后再试'
|
|
content: error.message || '请稍后再试'
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
@@ -468,31 +578,29 @@ let timer = null
|
|
|
|
|
|
|
|
// 轮询
|
|
// 轮询
|
|
|
const startPolling = () => {
|
|
const startPolling = () => {
|
|
|
- if (!timer) {
|
|
|
|
|
- timer = setInterval(async () => {
|
|
|
|
|
- await getAccounts()
|
|
|
|
|
- }, 5000)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!timer) {
|
|
|
|
|
+ timer = setInterval(async () => {
|
|
|
|
|
+ await getAccounts()
|
|
|
|
|
+ }, 5000)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 停止轮询
|
|
// 停止轮询
|
|
|
const stopPolling = () => {
|
|
const stopPolling = () => {
|
|
|
- if (timer) {
|
|
|
|
|
- clearInterval(timer)
|
|
|
|
|
- timer = null
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (timer) {
|
|
|
|
|
+ clearInterval(timer)
|
|
|
|
|
+ timer = null
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
onMounted(async () => {
|
|
|
- loading.value = true
|
|
|
|
|
- await getAccounts()
|
|
|
|
|
- loading.value = false
|
|
|
|
|
- startPolling()
|
|
|
|
|
|
|
+ getAccountsAsync()
|
|
|
|
|
+ startPolling()
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// 组件销毁时停止轮询
|
|
// 组件销毁时停止轮询
|
|
|
onUnmounted(() => {
|
|
onUnmounted(() => {
|
|
|
- stopPolling()
|
|
|
|
|
|
|
+ stopPolling()
|
|
|
})
|
|
})
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
@@ -501,9 +609,12 @@ onUnmounted(() => {
|
|
|
padding: 0 20px 20px 20px;
|
|
padding: 0 20px 20px 20px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.table {
|
|
|
|
|
- margin-top: 15px;
|
|
|
|
|
|
|
+.queryForm {
|
|
|
|
|
+ margin-top: 20px;
|
|
|
|
|
+ padding: 0 15px
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+.table {
|
|
|
.state {
|
|
.state {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|