Commit 40914323 by 李金轩

框架更改

1 parent 0223808e
Showing 91 changed files with 8269 additions and 4797 deletions
log
.DS_Store
node_modules/
node_modules
/dist
*.zip
dist.zip
label-cloud.zip
# local env files
.env.local
......
# label-cloud
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
This diff could not be displayed because it is too large.
{
"name": "label-cloud",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"dev": "vue-cli-service serve"
},
"dependencies": {
"ant-design-vue": "^2.2.0-beta.5",
"axios": "^0.21.1",
"core-js": "^3.6.5",
"element-plus": "^1.0.2-beta.28",
"jquery": "^3.6.0",
"js-cookie": "^2.2.1",
"less": "^4.1.1",
"less-loader": "^7.3.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"vue": "^3.2.22",
"vue-router": "^4.0.8",
"vuex": "^4.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0-0",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"vue-cli-plugin-element-plus": "~0.0.13"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
// window._serverHost = '36.112.68.214:12101'
window._serverHost = '101.201.36.180:12100' // 正式
// window._serverHost = '101.201.36.180:12200' // 测试
window._baseUrl = `http://${window._serverHost}`
window._serverHost2 = '101.201.36.180:12111'
// window._serverHost2 ='192.168.1.195:12101'
window._baseUrl2 = `http://${window._serverHost2}`
const log = console.log.bind(console)
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>logo.png">
<title>数据标注平台</title>
<script src="<%= BASE_URL %>config.js"></script>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
git status
git add *
git commit -m %1%
git pull
git push
git status
\ No newline at end of file
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<style lang="less">
html, body, #app, .el-container {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
::-webkit-scrollbar {
width: 9px;
}
::-webkit-scrollbar-thumb {
background-color: #dddddd;
background-clip: padding-box;
border-radius: 2em;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
}
::-webkit-scrollbar-thumb:hover {
background-color: #bbb;
}
.flex-vertical-center {
display: flex;
align-items: center;
}
.flex-horizontal-center {
display: flex;
justify-content: center;
}
</style>
import _ from 'lodash'
export const isEmptyValue = function(o) {
return [undefined, null].includes(o)
}
export const isNotEmptyValue = function(o) {
return !isEmptyValue(o)
}
export const isArray = function(o) {
return Array.isArray(o)
}
export const isNotArray = function(o) {
return !isArray(o)
}
export const isEmptyArray = function(o) {
return isArray(o) && o.length === 0
}
export const isNotEmptyArray = function(o) {
return !isEmptyArray(o)
}
export const isObject = function(o) {
return Object.prototype.toString.call(o) === '[object Object]'
}
export const isNotObject = function(o) {
return !isObject(o)
}
export const isEmptyObject = function(o) {
return isObject(o) && Object.keys(o).length === 0
}
export const isNotEmptyObject = function(o) {
return !isEmptyObject(o)
}
export const isDate = function(o) {
return Object.prototype.toString.call(o) === '[object Date]'
}
export const isNotDate = function(o) {
return !isDate(o)
}
export const isEqual = (value, other) => {
return _.isEqual(value, other)
}
export const isNotEqual = (value, other) => {
return !isEqual(value, other)
}
export const isOneOfTheseValues = function(value, expectedValueList) {
for (let expectedValue of expectedValueList)
{
if (isEqual(value, expectedValue))
{
return true
}
}
return false
}
export const isNoneOfTheseValues = function(value, unexpectedValueList) {
for (let unexpectedValue of unexpectedValueList)
{
if (isEqual(value, unexpectedValue))
{
return false
}
}
return true
}
import {isDate, isEmptyValue, isNoneOfTheseValues, isObject, isOneOfTheseValues} from "@/PublicUtil/Judgment"
import moment from "moment"
import _ from "lodash"
import Cookies from 'js-cookie'
export const getFolderColor = function(status) {
switch (status)
{
case 1:
{
return '#44D7B6'
}
case 2:
{
return '#F7B500'
}
case 3:
{
return '#6DD400'
}
case -1:
{
return '#6495ED'
}
case 4:
{
return '#FF69B4'
}
case 7:
{
return '#8B4513'
}
default:
{
return ''
}
}
}
export const getFolderTitle = function(status) {
switch (status)
{
case 1:
{
return '待标注'
}
case 2:
{
return '标注中'
}
case 3:
{
return '完成标注'
}
case -1:
{
return '被标注'
}
case 4:
{
return '优质'
}
case 7:
{
return '低质'
}
default:
{
return ''
}
}
}
export const getImageUrl = function(imageId) {
return `${window._baseUrl}/pics/image/${imageId}?token=${Cookies.get('token')}`
}
export const previewImage = function(imageUrl) {
window.open(imageUrl)
}
export const goBack = function() {
window.history.back()
}
export const getFormDataByObject = function(object) {
const formData = new FormData()
for (const key in object)
{
const value = object[key]
formData.append(key, value)
}
return formData
}
export const getCountGte = function() {
if (isEmptyValue(localStorage.getItem('countGTE')))
{
return 1
}
else
{
return localStorage.getItem('countGTE')
}
}
export const getCountLte = function() {
if (isEmptyValue(localStorage.getItem('countLTE')))
{
return 100
}
else
{
return localStorage.getItem('countLTE')
}
}
export const getFolderNum = function() {
if (isEmptyValue(localStorage.getItem('folderNum')))
{
return 10
}
else
{
return localStorage.getItem('folderNum')
}
}
export const getMinuteNum = function() {
if (isEmptyValue(localStorage.getItem('minuteNum')))
{
return 60
}
else
{
return localStorage.getItem('minuteNum')
}
}
export const getPagedList = function(list, columnNum) {
const baseArray = list
const len = baseArray.length
const lineNum = len % columnNum === 0 ? len / columnNum : Math.floor((len / columnNum) + 1)
let result = []
for (let i = 0; i < lineNum; i++)
{
// slice() 方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。且原始数组不会被修改。
const temp = baseArray.slice(i * columnNum, i * columnNum + columnNum)
result.push(temp)
}
return result
}
export const getKeyByValueInObject = function(object, value) {
return Object.keys(object).find(
(key) => {
return object[key] === value
}
)
}
export const filterEmptyValueInObject = function(object) {
if (isObject(object))
{
for (let key in object)
{
let value = object[key]
if (isOneOfTheseValues(value, ['', NaN, undefined, null]))
{
delete object[key]
}
}
return object
}
}
export const getTodayDate = function() {
return moment().startOf("day").format("yyyy-MM-DD")
}
export const setAccessedMenu = function(menu) {
localStorage.setItem('accessedMenu', encryptString(JSON.stringify(menu)))
}
export const getAccessedMenu = function() {
return JSON.parse(decryptString(localStorage.getItem('accessedMenu')))
}
/**
* encrypto 加密程序
* @param {Strng} str 待加密字符串
* @param {Number} xor 异或值
* @param {Number} hex 加密后的进制数
* @return {Strng} 加密后的字符串
*/
const encryptString = function(str, xor = 123, hex = 25) {
if (typeof str !== 'string' || typeof xor !== 'number' || typeof hex !== 'number')
{
return
}
let resultList = []
hex = hex <= 25 ? hex : hex % 25
for (let i = 0; i < str.length; i++)
{
// 提取字符串每个字符的ascll码
let charCode = str.charCodeAt(i)
// 进行异或加密
charCode = (charCode * 1) ^ xor
// 异或加密后的字符转成 hex 位数的字符串
charCode = charCode.toString(hex)
resultList.push(charCode)
}
let splitStr = String.fromCharCode(hex + 97)
let resultStr = resultList.join(splitStr)
return resultStr
}
/**
* decrypto 解密程序
* @param {Strng} str 待加密字符串
* @param {Number} xor 异或值
* @param {Number} hex 加密后的进制数
* @return {Strng} 加密后的字符串
*/
const decryptString = function(str, xor = 123, hex = 25) {
if (typeof str !== 'string' || typeof xor !== 'number' || typeof hex !== 'number')
{
return
}
let strCharList = []
let resultList = []
hex = hex <= 25 ? hex : hex % 25
// 解析出分割字符
let splitStr = String.fromCharCode(hex + 97)
// 分割出加密字符串的加密后的每个字符
strCharList = str.split(splitStr)
for (let i = 0; i < strCharList.length; i++)
{
// 将加密后的每个字符转成加密后的ascll码
let charCode = parseInt(strCharList[i], hex)
// 异或解密出原字符的ascll码
charCode = (charCode * 1) ^ xor
let strChar = String.fromCharCode(charCode)
resultList.push(strChar)
}
let resultStr = resultList.join('')
return resultStr
}
export const resetForm = function(form) {
for (let key in form)
{
form[key] = ""
}
}
export const emptyList = function(list) {
list.splice(0, list.length)
}
export const getTimestampString = function() {
return new Date().getTime().toString()
}
export const emptyObject = function(object) {
for (let key in object)
{
delete object[key]
}
}
export const cloneObject = function(targetObject, sourceObject) {
emptyObject(targetObject)
for (const key in sourceObject)
{
const value = sourceObject[key]
targetObject[key] = value
}
}
export const createFormData = function(object, fileName, file) {
let formData = new FormData()
if (isObject(object))
{
for (let key in object)
{
let value = object[key]
// if (![undefined, null].includes(value))
if (isNoneOfTheseValues(value, [undefined, null]))
{
formData.append(key, value)
}
}
}
if (file !== undefined)
{
formData.append(fileName, file)
}
return formData
}
export const copyDataList = function(targetDataList, sourceDataList) {
targetDataList.value.splice(0, targetDataList.value.length)
targetDataList.value.push(...sourceDataList)
}
export const formatPaginatedTableData = function(targetData, sourceData, total) {
const list = sourceData.list
// 添加序号
if (list !== undefined)
{
let start = (sourceData.pageNum - 1) * sourceData.pageSize
let end = start + list.length
for (let i = start; i < end; i++)
{
let item = list[i - start]
item["serialNumber"] = i + 1
}
}
copyDataList(targetData, list)
total.value = sourceData.total
}
export const addSerialNumber = function(sourceData) {
if (sourceData !== undefined)
{
for (let i = 0; i < sourceData.length; i++)
{
let item = sourceData[i]
item["serialNumber"] = i + 1
}
}
}
// 把 date 对象转换为 0000-00-00 这种日期形式
export const formatDate = function(date) {
if (isDate(date))
{
return moment(date).format("YYYY-MM-DD")
}
}
import {axiosInstance} from "@/Request/PublicAxiosInstance"
import {} from "@/PublicUtil/PublicUtil"
import imagePackageApi from '@/views/DataLabel/ImagePackage/ImagePackageApi'
export const getUserNameIdMap = function(targetData) {
axiosInstance.request(
{
method: 'GET',
url: `/users`,
}
).then(
(r) => {
const list = r.data
for (const item of list)
{
targetData[item.name] = item.id
}
}
)
}
export const getCompanyMap = function(targetData) {
axiosInstance.request(
{
method: 'GET',
url: `/accounts`,
}
).then(
(r) => {
const list = r.data
for (const item of list)
{
targetData[item.id] = item.name
}
}
)
}
export const getImagePackageMap = function(targetData) {
imagePackageApi.getImagePackageList().then(
(r) => {
const list = r.data
for (const item of list)
{
targetData[item.name] = item.id
}
}
)
}
export const getCanCreateUsernameIdMap = function() {
const currentUserType = localStorage.getItem('currentUserType')
switch (currentUserType)
{
case '0': // 超级管理员
{
return {
"超级管理员": 0,
"项目经理": 1,
"内部质检员": 2,
"外部管理员": 3,
"外部质检员": 4,
"外部标注员": 5,
"兼职标注员": 6,
"数据清洗员": 7,
}
}
case '1': // 项目经理
{
return {
"内部质检员": 2,
"外部管理员": 3,
"外部质检员": 4,
"外部标注员": 5,
"兼职标注员": 6,
}
}
case '3': // 外部管理员
{
return {
"外部质检员": 4,
"外部标注员": 5,
"兼职标注员": 6,
}
}
default:
{
return {}
}
}
}
import axios from 'axios'
import router from '@/router/index'
import Cookies from "js-cookie"
import {getTimestampString} from "@/PublicUtil/PublicUtil"
// 创建 axios 的一个实例
const axiosInstance = axios.create(
{
baseURL: window._baseUrl
}
)
const axiosInstance2 = axios.create(
{
baseURL: window._baseUrl2,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
)
// 请求拦截器
axiosInstance.interceptors.request.use(
config => {
config.headers.token = Cookies.get('token')
return config
}
)
// 响应拦截器
axiosInstance.interceptors.response.use(
(r) => {
const responseData = r.data
const message = responseData.msg
if (message === '当前会话未登录')
{
router.push(
'/'
)
}
else
{
return responseData
}
},
(e) => {
const responseData = e.response
return responseData
}
)
axiosInstance2.interceptors.response.use(
(r) => {
const responseData = r.data
return responseData
},
(e) => {
const responseData = e.response
return responseData
}
)
export {axiosInstance, axiosInstance2}
import {createApp} from 'vue'
import App from './App.vue'
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
import router from './router'
import store from './store'
import installElementPlus from './plugins/element'
const app = createApp(App)
installElementPlus(app)
app.use(store)
app.use(router)
app.use(Antd)
app.mount('#app')
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
import locale from 'element-plus/lib/locale/lang/zh-cn'
export default (app) => {
app.use(ElementPlus, {locale})
}
import {createRouter, createWebHashHistory} from 'vue-router'
const menuRoute = [
{
path: '/DataLabel',
component: () => import("@/views/Main/Main.vue"),
children: [
{
path: 'ImagePackage',
component: () => import("@/views/DataLabel/ImagePackage/ImagePackage.vue"),
},
{
path: 'PeopleLabel',
component: () => import("@/views/DataLabel/PeopleLabel/PeopleLabel.vue"),
},
{
path: 'Labeling',
component: () => import("@/views/DataLabel/Labeling/Labeling.vue"),
},
{
path: 'SubmitQualityInspect',
component: () => import("@/views/DataLabel/SubmitQualityInspect/SubmitQualityInspect.vue"),
},
{
path: 'LabelWorkbook',
component: () => import("@/views/DataLabel/LabelWorkbook/LabelWorkbook.vue"),
},
]
},
{
path: '/QualityInspect',
component: () => import("@/views/Main/Main.vue"),
children: [
{
path: 'QualityInspectExamine',
component: () => import("@/views/QualityInspect/QualityInspectExamine/QualityInspectExamine.vue"),
},
]
},
{
path: '/Project',
component: () => import("@/views/Main/Main.vue"),
children: [
{
path: 'ProjectManagement',
component: () => import("@/views/Project/ProjectManagement/ProjectManagement.vue"),
},
]
},
{
path: '/BackgroundManagement',
component: () => import("@/views/Main/Main.vue"),
children: [
{
path: 'OutsourceCompany',
component: () => import("@/views/BackgroundManagement/OutsourceCompany/OutsourceCompany.vue"),
},
{
path: 'UserManagement',
component: () => import("@/views/BackgroundManagement/UserManagement/UserManagement.vue"),
},
]
},
{
path: '/DataClean',
component: () => import("@/views/Main/Main.vue"),
children: [
{
path: 'DataClean',
component: () => import("@/views/DataClean/DataClean/DataClean.vue"),
},
{
path: 'CleanManagement',
component: () => import("@/views/DataClean/CleanManagement/CleanManagement.vue"),
},
]
},
]
const route = [
{
path: '/',
redirect: '/Login',
},
{
path: '/Test',
component: () => import("@/views/Test/Test.vue"),
},
{
path: '/Login',
component: () => import("@/views/Login/Login.vue"),
},
{
path: '/ClassAmongClean',
component: () => import("@/views/Main/Main.vue"),
children: [
{
path: '',
component: () => import("@/views/ClassAmongClean/ClassAmongClean.vue"),
},
]
},
{
path: '/ClassInsideClean',
component: () => import("@/views/Main/Main.vue"),
children: [
{
path: '',
component: () => import("@/views/ClassInsideClean/ClassInsideClean.vue"),
},
]
},
{
path: '/JudgePeople',
component: () => import("@/views/Main/Main.vue"),
children: [
{
path: '',
component: () => import("@/views/JudgePeople/JudgePeople.vue"),
},
]
},
{
path: '/ClassInsideJudgePerson',
component: () => import("@/views/Main/Main.vue"),
children: [
{
path: '',
component: () => import("@/views/ClassInsideJudgePerson/ClassInsideJudgePerson.vue"),
},
]
},
...menuRoute
]
export const getUrlByTitle = function(title) {
const map = {
"标注": '/DataLabel/ImagePackage',
"提交质检": '/DataLabel/SubmitQualityInspect',
"标注工作薄": '/DataLabel/LabelWorkbook',
"质检审核": '/QualityInspect/QualityInspectExamine',
"项目管理": '/Project/ProjectManagement',
"外包公司": '/BackgroundManagement/OutsourceCompany',
"用户管理": '/BackgroundManagement/UserManagement',
"数据清洗": '/DataClean/DataClean',
"清洗管理": '/DataClean/CleanManagement',
}
return map[title]
}
const router = createRouter(
{
history: createWebHashHistory(),
routes: route
}
)
export default router
import {createStore} from 'vuex'
export default createStore(
{
state: {
accessedRouteList: [],
},
mutations: {
setAccessedRouteList(state, accessedRouteList) {
state.accessedRouteList = accessedRouteList
},
},
}
)
<template>
<a-layout>
<a-layout-sider v-model:collapsed="collapsed" :trigger="null" collapsible>
<div class="logo"/>
<a-menu theme="dark" mode="inline" v-model:selectedKeys="selectedKeys">
<a-menu-item key="1">
<user-outlined/>
<span>nav 1</span>
</a-menu-item>
<a-menu-item key="2">
<video-camera-outlined/>
<span>nav 2</span>
</a-menu-item>
<a-menu-item key="3">
<upload-outlined/>
<span>nav 3</span>
</a-menu-item>
</a-menu>
</a-layout-sider>
<a-layout>
<a-layout-header style="background: #fff; padding: 0">
<menu-unfold-outlined
v-if="collapsed"
class="trigger"
@click="() => (collapsed = !collapsed)"
/>
<menu-fold-outlined v-else class="trigger" @click="() => (collapsed = !collapsed)"/>
</a-layout-header>
<a-layout-content
:style="{ margin: '24px 16px', padding: '24px', background: '#fff', minHeight: '280px' }"
>
Content
</a-layout-content>
</a-layout>
</a-layout>
</template>
<script>
import {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
MenuUnfoldOutlined,
MenuFoldOutlined,
} from '@ant-design/icons-vue'
import {defineComponent, ref} from 'vue'
export default defineComponent({
components: {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
MenuUnfoldOutlined,
MenuFoldOutlined,
},
setup() {
return {
selectedKeys: ref(['1']),
collapsed: ref(false),
}
},
})
</script>
<style>
</style>
<template>
<el-container class="OutsourceCompanyManagement">
<el-header height="50px">
<div>
<span class="title-text">外包公司</span>
</div>
</el-header>
<el-main>
<el-button type="primary" @click="addOutsourceCompany">新建</el-button>
<el-table :data="outsourceCompanyList" v-loading="isLoading">
<el-table-column prop="name" label="名称" align="center"></el-table-column>
<el-table-column prop="description" label="描述" align="center"></el-table-column>
<el-table-column prop="description" label="状态" align="center">
<template #default="scope">
{{ getStatusTitle(scope.row.status) }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
<el-table-column prop="operation" label="操作" align="center">
<template #default="scope">
<el-button @click="prohibitOutsourceCompany(scope.row.id)" type="text">禁用</el-button>
<el-button @click="resumeOutsourceCompany(scope.row.id)" type="text">解禁</el-button>
<el-button @click="editOutsourceCompany(scope.row)" type="text">编辑</el-button>
<el-button @click="confirmDeleteOutsourceCompany(scope.row.id)" type="text">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-drawer title="新建外包公司" v-model="addOutsourceCompanyVisible" :destroy-on-close="true" :direction="'rtl'">
<div class="outsourceCompany-form">
<el-form :model="addOutsourceCompanyForm" :rules="rules" ref="ref_addOutsourceCompanyForm">
<el-form-item label="公司名称:" prop="outsourceCompanyName" :label-width="'120px'">
<el-input v-model.trim="addOutsourceCompanyForm.name"></el-input>
</el-form-item>
<el-form-item label="管理人:" prop="outsourceCompanyYear" :label-width="'120px'">
<el-select v-model="addOutsourceCompanyForm.managerId" style="width: 100%">
<el-option v-for="(value, name) in userNameIdMap" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="管理人电话:" prop="groupId" :label-width="'120px'">
<el-input v-model.trim="addOutsourceCompanyForm.description"></el-input>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="addOutsourceCompanyVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmAddOutsourceCompany">确 定</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
<el-drawer title="编辑外包公司" v-model="editOutsourceCompanyVisible" :destroy-on-close="true" :direction="'rtl'">
<div class="outsourceCompany-form">
<el-form :model="editOutsourceCompanyForm" :rules="rules" ref="ref_editOutsourceCompanyForm">
<el-form-item label="公司名称:" prop="outsourceCompanyName" :label-width="'120px'">
<el-input v-model.trim="editOutsourceCompanyForm.name"></el-input>
</el-form-item>
<el-form-item label="管理人:" prop="outsourceCompanyYear" :label-width="'120px'">
<el-select v-model="editOutsourceCompanyForm.managerId" style="width: 100%">
<el-option v-for="(value, name) in userNameIdMap" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="管理人电话:" prop="groupId" :label-width="'120px'">
<el-input v-model.trim="editOutsourceCompanyForm.description"></el-input>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="editOutsourceCompanyVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmEditOutsourceCompany">确 定</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
</el-main>
</el-container>
</template>
<script>
import {computed, onMounted, reactive, ref, toRaw, toRefs, watch} from "vue"
import {
filterEmptyValueInObject,
resetForm
} from "@/PublicUtil/PublicUtil"
import outsourceCompanyApi from './OutsourceCompanyApi'
import {ElMessageBox} from 'element-plus'
import {ElMessage} from 'element-plus'
import moment from "moment"
import {getUserNameIdMap} from '@/Request/DictionaryRequest'
export default {
setup() {
// scalar
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref()
const isLoading = ref(false)
const addOutsourceCompanyVisible = ref(false)
const editOutsourceCompanyVisible = ref(false)
const outsourceCompanyList = ref([])
const ref_addOutsourceCompanyForm = ref()
const ref_editOutsourceCompanyForm = ref()
// computed
// mapping
const rules = reactive(
{
// outsourceCompanyName: [
// {
// required: true,
// message: '请输入外包公司名称',
// },
// ],
// outsourceCompanyYear: [
// {
// type: 'date',
// required: true,
// message: '请输入建成年份',
// trigger: 'change'
// }
// ],
// groupId: [
// {
// required: true,
// message: '请选择集团',
// },
// ],
}
)
const userNameIdMap = reactive({})
const addOutsourceCompanyForm = reactive(
{
name: '', // 公司名
managerId: '', // 管理人Id
description: '', // 电话
}
)
const editOutsourceCompanyForm = reactive(
{
name: '', // 公司名
managerId: '', // 管理人Id
description: '', // 电话
id: '',
}
)
// function
const handlePageNumChange = function(num) {
pageNum.value = num
getOutsourceCompanyList()
}
const handlePageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
getOutsourceCompanyList()
}
const confirmAddOutsourceCompany = function() {
ref_addOutsourceCompanyForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(addOutsourceCompanyForm)
const data = filterEmptyValueInObject(rawData)
outsourceCompanyApi.addOutsourceCompany(data).then(
(r) => {
addOutsourceCompanyVisible.value = false
const message = r.msg
ElMessage(`${message}`)
getOutsourceCompanyList()
}
)
}
}
)
}
const editOutsourceCompany = function(row) {
editOutsourceCompanyVisible.value = true
editOutsourceCompanyForm.id = row.id
editOutsourceCompanyForm.name = row.name
editOutsourceCompanyForm.managerId = row.managerId
editOutsourceCompanyForm.description = row.description
}
const confirmEditOutsourceCompany = function() {
ref_editOutsourceCompanyForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(editOutsourceCompanyForm)
const data = filterEmptyValueInObject(
{
name: rawData.name,
managerId: rawData.managerId,
description: rawData.description,
}
)
outsourceCompanyApi.editOutsourceCompany(rawData.id, data).then(
(r) => {
const message = r.msg
getOutsourceCompanyList()
ElMessage(`${message}`)
}
)
editOutsourceCompanyVisible.value = false
}
}
)
}
const confirmDeleteOutsourceCompany = function(id) {
ElMessageBox.confirm(
"删除后此外包公司相关数据全部都会消失,你确定要删除吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(
() => {
outsourceCompanyApi.deleteOutsourceCompany(id).then(
(r) => {
const message = r.msg
getOutsourceCompanyList()
ElMessage(`${message}`)
}
)
}
)
}
const addOutsourceCompany = function() {
resetForm(addOutsourceCompanyForm)
addOutsourceCompanyVisible.value = true
}
const getOutsourceCompanyList = function() {
isLoading.value = true
outsourceCompanyApi.getOutsourceCompanyList().then(
({data}) => {
isLoading.value = false
outsourceCompanyList.value = data
log(444, data)
// formatPaginatedTableData(
// outsourceCompanyList,
// data,
// total,
// )
}
)
}
const getStatusTitle = function(status) {
switch (status)
{
case 0:
{
return '禁用中'
}
case 1:
{
return '使用中'
}
default:
{
break
}
}
}
const prohibitOutsourceCompany = function(id) {
ElMessageBox.confirm(
"确定要禁用该公司?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(
() => {
outsourceCompanyApi.prohibitOutsourceCompany(id).then(
(r) => {
const message = r.msg
getOutsourceCompanyList()
ElMessage(`${message}`)
}
)
}
)
}
const resumeOutsourceCompany = function(id) {
ElMessageBox.confirm(
"确定要解禁该公司?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(
() => {
outsourceCompanyApi.resumeOutsourceCompany(id).then(
(r) => {
const message = r.msg
getOutsourceCompanyList()
ElMessage(`${message}`)
}
)
}
)
}
const initialize = function() {
getOutsourceCompanyList()
getUserNameIdMap(userNameIdMap)
}
initialize()
return {
// scalar
pageNum,
pageSize,
total,
isLoading,
outsourceCompanyList,
ref_addOutsourceCompanyForm,
ref_editOutsourceCompanyForm,
addOutsourceCompanyVisible,
editOutsourceCompanyVisible,
// mapping
userNameIdMap,
addOutsourceCompanyForm,
editOutsourceCompanyForm,
rules,
// function
handlePageNumChange,
handlePageSizeChange,
addOutsourceCompany,
editOutsourceCompany,
confirmEditOutsourceCompany,
confirmAddOutsourceCompany,
confirmDeleteOutsourceCompany,
prohibitOutsourceCompany,
resumeOutsourceCompany,
getStatusTitle,
}
},
}
</script>
<style lang="less" scoped>
@import "./OutsourceCompany.less";
</style>
import {axiosInstance} from '@/Request/PublicAxiosInstance'
import {filterEmptyValueInObject} from "@/PublicUtil/PublicUtil"
class OutsourceCompanyApi {
getOutsourceCompanyList() {
return axiosInstance.request(
{
method: 'GET',
url: '/accounts',
}
)
}
addOutsourceCompany(data) {
return axiosInstance.request(
{
method: 'POST',
url: '/accounts',
data: filterEmptyValueInObject(
{
name: data.name,
managerId: data.managerId,
description: data.description,
createUser: localStorage.getItem('currentUserId'),
}
)
}
)
}
editOutsourceCompany(id, data) {
return axiosInstance.request(
{
method: 'POST',
url: `/accounts/${id}`,
data: data
}
)
}
deleteOutsourceCompany(id) {
return axiosInstance.request(
{
method: 'DELETE',
url: `/accounts/${id}`,
}
)
}
prohibitOutsourceCompany(id) {
return axiosInstance.request(
{
method: 'POST',
url: `/accounts/${id}`,
data: {
status: 0
}
}
)
}
resumeOutsourceCompany(id) {
return axiosInstance.request(
{
method: 'POST',
url: `/accounts/${id}`,
data: {
status: 1
}
}
)
}
getUserList() {
return axiosInstance.request(
{
method: 'GET',
url: `/users`,
}
)
}
}
const outsourceCompanyApi = new OutsourceCompanyApi()
export default outsourceCompanyApi
<template>
<el-container class="UserManagement">
<el-header height="50px">
<div>
<span class="title-text">用户管理</span>
</div>
</el-header>
<el-main>
<el-button type="primary" @click="addUser">新建</el-button>
<el-table :data="userList" v-loading="isLoading">
<el-table-column prop="name" label="用户名称" align="center"></el-table-column>
<el-table-column prop="username" label="账号" align="center"></el-table-column>
<el-table-column prop="accountId" label="所属公司" align="center">
<template #default="scope">
{{ companyMap[scope.row.accountId] }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
<el-table-column prop="operation" label="操作" align="center">
<template #default="scope">
<el-button @click="editUser(scope.row)" type="text">编辑
</el-button>
<el-button @click="confirmDeleteUser(scope.row.id)" type="text">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-drawer title="新建用户" v-model="addUserVisible" :destroy-on-close="true" :direction="'rtl'">
<div class="user-form">
<el-form :model="addUserForm" :rules="rules" ref="ref_addUserForm">
<el-form-item label="用户名称:" prop="username" :label-width="'120px'">
<el-input v-model.trim="addUserForm.name"></el-input>
</el-form-item>
<el-form-item label="账号:" prop="name" :label-width="'120px'">
<el-input v-model.trim="addUserForm.username" style="width: 100%"></el-input>
</el-form-item>
<el-form-item label="密码:" prop="password" :label-width="'120px'">
<el-input v-model.trim="addUserForm.password"></el-input>
</el-form-item>
<el-form-item label="所属公司:" prop="accountId" :label-width="'120px'">
<el-select v-model="addUserForm.accountId" style="width: 100%">
<el-option v-for="(name, value) in companyMap" :label="name" :value="parseInt(value)"></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据权限管理:" prop="type" :label-width="'120px'">
<el-select v-model="addUserForm.type" style="width: 100%">
<el-option v-for="(value, name) in getCanCreateUsernameIdMap()" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="addUserVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmAddUser">确 定</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
<el-drawer title="编辑用户" v-model="editUserVisible" :destroy-on-close="true" :direction="'rtl'">
<div class="user-form">
<el-form :model="editUserForm" :rules="rules" ref="ref_editUserForm">
<el-form-item label="用户名称:" prop="username" :label-width="'120px'">
<el-input v-model.trim="editUserForm.name"></el-input>
</el-form-item>
<el-form-item label="账号:" prop="name" :label-width="'120px'">
<el-input v-model.trim="editUserForm.username" style="width: 100%"></el-input>
</el-form-item>
<el-form-item label="密码:" prop="password" :label-width="'120px'">
<el-input v-model.trim="editUserForm.password"></el-input>
</el-form-item>
<el-form-item label="所属公司:" prop="accountId" :label-width="'120px'">
<el-select v-model="editUserForm.accountId" style="width: 100%">
<el-option v-for="(name, value) in companyMap" :label="name" :value="parseInt(value)"></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据权限管理:" prop="type" :label-width="'120px'">
<el-select v-model="editUserForm.type" style="width: 100%">
<el-option v-for="(value, name) in getCanCreateUsernameIdMap()" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="editUserVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmEditUser">确 定</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
</el-main>
</el-container>
</template>
<script>
import {reactive, ref, toRaw,} from "vue"
import {
filterEmptyValueInObject, getKeyByValueInObject,
resetForm
} from "@/PublicUtil/PublicUtil"
import userApi from './UserManagementApi'
import {ElMessageBox} from 'element-plus'
import {ElMessage} from 'element-plus'
import {getCanCreateUsernameIdMap, getCompanyMap} from '@/Request/DictionaryRequest'
export default {
setup() {
// scalar
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref()
const isLoading = ref(false)
const addUserVisible = ref(false)
const editUserVisible = ref(false)
const userList = ref([])
const ref_addUserForm = ref()
const ref_editUserForm = ref()
// computed
// mapping
const rules = reactive(
{
// userName: [
// {
// required: true,
// message: '请输入用户名称',
// },
// ],
// userYear: [
// {
// type: 'date',
// required: true,
// message: '请输入建成年份',
// trigger: 'change'
// }
// ],
// groupId: [
// {
// required: true,
// message: '请选择集团',
// },
// ],
}
)
const companyMap = reactive({})
const addUserForm = reactive(
{
username: '', // 用户名称
name: '', // 账号
password: '', // 密码
accountId: '', // 所属公司
type: '', // 数据权限管理
}
)
const editUserForm = reactive(
{
username: '', // 用户名称
name: '', // 账号
password: '', // 密码
accountId: '', // 所属公司
type: '', // 数据权限管理
id: '',
}
)
// function
const handlePageNumChange = function(num) {
pageNum.value = num
getUserList()
}
const handlePageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
getUserList()
}
const confirmAddUser = function() {
ref_addUserForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(addUserForm)
const data = filterEmptyValueInObject(rawData)
userApi.addUser(data).then(
(r) => {
addUserVisible.value = false
const message = r.msg
ElMessage(`${message}`)
getUserList()
}
)
}
}
)
}
const editUser = function(row) {
editUserVisible.value = true
editUserForm.username = row.username
editUserForm.name = row.name
editUserForm.password = row.password
editUserForm.accountId = row.accountId
editUserForm.type = row.type
editUserForm.id = row.id
}
const confirmEditUser = function() {
ref_editUserForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(editUserForm)
const data = filterEmptyValueInObject(
{
username: rawData.username,
name: rawData.name,
password: rawData.password,
accountId: rawData.accountId,
type: rawData.type,
}
)
userApi.editUser(rawData.id, data).then(
(r) => {
const message = r.msg
getUserList()
ElMessage(`${message}`)
}
)
editUserVisible.value = false
}
}
)
}
const confirmDeleteUser = function(id) {
ElMessageBox.confirm(
"删除后此用户相关数据全部都会消失,你确定要删除吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(
() => {
userApi.deleteUser(id).then(
(r) => {
const message = r.msg
getUserList()
ElMessage(`${message}`)
}
)
}
)
}
const addUser = function() {
resetForm(addUserForm)
addUserVisible.value = true
}
const getUserList = function() {
isLoading.value = true
userApi.getUserList().then(
({data}) => {
isLoading.value = false
userList.value = data
// formatPaginatedTableData(
// userList,
// data,
// total,
// )
}
)
}
const initialize = function() {
getUserList()
getCompanyMap(companyMap)
}
initialize()
return {
// scalar
pageNum,
pageSize,
total,
isLoading,
userList,
ref_addUserForm,
ref_editUserForm,
addUserVisible,
editUserVisible,
// mapping
companyMap,
addUserForm,
editUserForm,
rules,
// function
handlePageNumChange,
handlePageSizeChange,
addUser,
editUser,
confirmEditUser,
confirmAddUser,
confirmDeleteUser,
getCanCreateUsernameIdMap,
getKeyByValueInObject,
}
},
}
</script>
<style lang="less" scoped>
@import "./UserManagement.less";
</style>
import {axiosInstance} from '@/Request/PublicAxiosInstance'
import {filterEmptyValueInObject, } from "@/PublicUtil/PublicUtil"
class UserApi {
getUserList() {
return axiosInstance.request(
{
method: 'GET',
url: '/users',
}
)
}
addUser(data) {
return axiosInstance.request(
{
method: 'POST',
url: '/users',
data: filterEmptyValueInObject(
{
username: data.username,
name: data.name,
password: data.password,
accountId: data.accountId,
type: data.type,
createUser: localStorage.getItem('currentUserId'),
}
)
}
)
}
editUser(id, data) {
return axiosInstance.request(
{
method: 'POST',
url: `/users/${id}`,
data: data
}
)
}
deleteUser(id) {
return axiosInstance.request(
{
method: 'DELETE',
url: `/users/${id}`,
}
)
}
}
const userApi = new UserApi()
export default userApi
import {axiosInstance2} from '@/Request/PublicAxiosInstance'
import {filterEmptyValueInObject,} from "@/PublicUtil/PublicUtil"
class DataCleanApi {
getDataCleanList(data) {
return axiosInstance2.request(
{
method: 'GET',
url: '/clean2/list',
params: filterEmptyValueInObject(
{
packId: data.packId,
status: data.status,
pageNum: data.pageNum,
pageSize: data.pageSize,
}
)
}
)
}
getCleanAmongResult(data) {
return axiosInstance2.request(
{
method: 'GET',
url: '/clean2/getClean2',
params: filterEmptyValueInObject(
{
id: data.id,
packId: data.packId,
}
)
}
)
}
}
const dataCleanApi = new DataCleanApi()
export default dataCleanApi
<template>
<el-container class="DataClean">
<el-header height="auto">
<span class="title-text">类间清洗</span>
<div style="display: flex; justify-content:flex-end">
<el-button @click="goBack">返回上一页</el-button>
</div>
<div style="font-size: 20px">任务名:{{ name }}</div>
<div style="font-size: 20px">批次:{{ packName }}</div>
<el-menu mode="horizontal" @select="onMenuSelect" :default-active="''">
<el-menu-item :index="'0'">
未处理
</el-menu-item>
<el-menu-item :index="'1'">
已处理
</el-menu-item>
<el-menu-item :index="''">
全部
</el-menu-item>
</el-menu>
</el-header>
<el-main>
<el-table :data="dataCleanList" v-loading="isLoading">
<el-table-column prop="personId" label="左侧ID" align="center"></el-table-column>
<el-table-column prop="simPersonId" label="右侧ID" align="center"></el-table-column>
<el-table-column prop="same" label="是否是同一个人" align="center">
<template #default="scope">
{{ getSameTitle(scope.row.same) }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" align="center">
<template #default="scope">
{{ getStatusTitle(scope.row.status) }}
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" align="center">
<template #default="scope">
<el-button @click="gotoHandle(scope.row)" type="text">进入</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination @current-change="onPageNumChange"
@size-change="onPageSizeChange"
:current-page="pageNum"
:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 40, 80]"
layout="total, sizes, prev, pager, next, jumper"
style="text-align:center"
>
</el-pagination>
</el-main>
</el-container>
</template>
<script>
import {computed, onMounted, reactive, ref, toRaw, toRefs, watch} from "vue"
import {
filterEmptyValueInObject, goBack,
resetForm
} from "@/PublicUtil/PublicUtil"
import dataCleanApi from './ClassAmongClean'
import {ElMessageBox} from 'element-plus'
import {ElMessage} from 'element-plus'
import {getImagePackageMap, getUserNameIdMap} from '@/Request/DictionaryRequest'
import router from '@/router'
import {useRoute, useRouter} from 'vue-router'
export default {
setup() {
// scalar
const packId = useRoute().query.packId
const name = useRoute().query.name
const packName = useRoute().query.packName
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref()
const isLoading = ref(false)
const addDataCleanVisible = ref(false)
const editDataCleanVisible = ref(false)
const dataCleanList = ref([])
const ref_addDataCleanForm = ref()
const ref_editDataCleanForm = ref()
const router = useRouter()
let selectedMenuIndex = ''
// computed
// mapping
const rules = reactive(
{}
)
const userNameIdMap = reactive({})
const imagePackageMap = reactive({})
const addDataCleanForm = reactive(
{
packId: '',
name: '',
}
)
const editDataCleanForm = reactive(
{
packId: '',
name: '',
}
)
// function
const onPageNumChange = function(num) {
pageNum.value = num
getDataCleanList()
}
const onPageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
getDataCleanList()
}
const confirmAddDataClean = function() {
ref_addDataCleanForm.value.validate(
(isValid) => {
if (isValid)
{
addDataCleanVisible.value = false
const rawData = toRaw(addDataCleanForm)
const data = filterEmptyValueInObject(rawData)
dataCleanApi.addDataClean(data).then(
(r) => {
const message = r.msg
ElMessage(`${message}`)
getDataCleanList()
}
)
}
}
)
}
const editDataClean = function(row) {
editDataCleanVisible.value = true
editDataCleanForm.id = row.id
editDataCleanForm.name = row.name
editDataCleanForm.managerId = row.managerId
editDataCleanForm.description = row.description
}
const confirmEditDataClean = function() {
ref_editDataCleanForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(editDataCleanForm)
const data = filterEmptyValueInObject(
{
name: rawData.name,
managerId: rawData.managerId,
description: rawData.description,
}
)
dataCleanApi.editDataClean(rawData.id, data).then(
(r) => {
const message = r.msg
getDataCleanList()
ElMessage(`${message}`)
}
)
editDataCleanVisible.value = false
}
}
)
}
const confirmDeleteDataClean = function(id) {
ElMessageBox.confirm(
"删除后此数据清洗相关数据全部都会消失,你确定要删除吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(
() => {
dataCleanApi.deleteDataClean(id).then(
(r) => {
const message = r.msg
getDataCleanList()
ElMessage(`${message}`)
}
)
}
)
}
const addDataClean = function() {
resetForm(addDataCleanForm)
addDataCleanVisible.value = true
}
const getDataCleanList = function() {
isLoading.value = true
dataCleanApi.getDataCleanList({
packId: packId,
status: selectedMenuIndex,
pageNum: pageNum.value,
pageSize: pageSize.value,
}).then(
({data}) => {
isLoading.value = false
dataCleanList.value = data.list
total.value = data.total
}
)
}
const getStatusTitle = function(status) {
switch (status)
{
case 0:
{
return '未处理'
}
case 1:
{
return '已处理'
}
case 2:
{
return '处理中'
}
default:
{
break
}
}
}
const getTypeTitle = function(status) {
switch (status)
{
case 1:
{
return '类内清洗'
}
case 2:
{
return '类间清洗'
}
{
break
}
}
}
const gotoHandle = function(row) {
const data = {
id: row.id,
packId: row.packId,
}
dataCleanApi.getCleanAmongResult(data).then(
({data}) => {
router.push(
{
path: '/JudgePeople',
query: {
id: row.id,
packId: row.packId,
leftPersonId: data.personId,
rightPersonId: data.simPersonId,
same: getSameTitle(row.same),
name: name,
packName: packName,
personId: row.personId,
}
}
)
}
)
}
const onMenuSelect = function(index) {
selectedMenuIndex = index
getDataCleanList()
}
const getSameTitle = function(same) {
switch (same)
{
case 0:
{
return '不是'
}
case 1:
{
return '是'
}
default:
{
break
}
}
}
// const goBack = function() {
// router.push(
// {
// path: '/DataClean/DataClean',
// }
// )
// }
const initialize = function() {
getDataCleanList()
getUserNameIdMap(userNameIdMap)
getImagePackageMap(imagePackageMap)
}
initialize()
return {
// scalar
name,
packName,
pageNum,
pageSize,
total,
isLoading,
dataCleanList,
ref_addDataCleanForm,
ref_editDataCleanForm,
addDataCleanVisible,
editDataCleanVisible,
// mapping
userNameIdMap,
imagePackageMap,
addDataCleanForm,
editDataCleanForm,
rules,
// function
onPageNumChange,
onPageSizeChange,
addDataClean,
editDataClean,
confirmEditDataClean,
confirmAddDataClean,
confirmDeleteDataClean,
gotoHandle,
getStatusTitle,
getTypeTitle,
getSameTitle,
onMenuSelect,
goBack,
}
},
}
</script>
<style lang="less" scoped>
@import "./ClassAmongClean.less";
</style>
import {axiosInstance2} from '@/Request/PublicAxiosInstance'
import {filterEmptyValueInObject, getFormDataByObject} from "@/PublicUtil/PublicUtil"
class ClassInsideCleanApi {
getClassInsideCleanList(data) {
return axiosInstance2.request(
{
method: 'GET',
url: '/clean1-person/list',
params: filterEmptyValueInObject(
{
packId: data.packId,
status: data.status,
pageNum: data.pageNum,
pageSize: data.pageSize,
}
)
}
)
}
getCleanInsideResult(data) {
return axiosInstance2.request(
{
method: 'GET',
url: '/clean1-person/getClean1',
params: {
personId: data.personId,
packId: data.packId,
}
}
)
}
split(data) {
return axiosInstance2.request(
{
method: 'POST',
url: '/clean1-person/split',
data: getFormDataByObject(
{
personId: data.personId,
packId: data.packId,
picIds: data.picIds,
}
)
}
)
}
}
const classInsideCleanApi = new ClassInsideCleanApi()
export default classInsideCleanApi
<template>
<el-container class="DataClean">
<el-header height="auto">
<span class="title-text">类内清洗</span>
<div style="display: flex; justify-content:flex-end">
<el-button @click="goBack">返回上一页</el-button>
</div>
<div style="font-size: 20px">任务名:{{ name }}</div>
<div style="font-size: 20px">批次:{{ packName }}</div>
<el-menu mode="horizontal" @select="onMenuSelect" :default-active="''">
<el-menu-item :index="'0'">
未处理
</el-menu-item>
<el-menu-item :index="'1'">
已处理
</el-menu-item>
<el-menu-item :index="''">
全部
</el-menu-item>
</el-menu>
</el-header>
<el-main>
<el-table :data="dataCleanList" v-loading="isLoading">
<el-table-column prop="personId" label="ID" align="center"></el-table-column>
<el-table-column prop="status" label="状态" align="center">
<template #default="scope">
{{ getStatusTitle(scope.row.status) }}
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" align="center">
<template #default="scope">
<el-button @click="gotoHandle(scope.row)" type="text">进入处理</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination @current-change="onPageNumChange"
@size-change="onPageSizeChange"
:current-page="pageNum"
:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 40, 80]"
layout="total, sizes, prev, pager, next, jumper"
style="text-align:center"
>
</el-pagination>
</el-main>
</el-container>
</template>
<script>
import {computed, onMounted, reactive, ref, toRaw, toRefs, watch} from "vue"
import {
filterEmptyValueInObject, goBack,
resetForm
} from "@/PublicUtil/PublicUtil"
import classInsideCleanApi from './ClassInsideClean'
import {ElMessageBox} from 'element-plus'
import {ElMessage} from 'element-plus'
import {getImagePackageMap, getUserNameIdMap} from '@/Request/DictionaryRequest'
import router from '@/router'
import {useRoute, useRouter} from 'vue-router'
export default {
setup() {
// scalar
const packId = useRoute().query.packId
const name = useRoute().query.name
const packName = useRoute().query.packName
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref()
const isLoading = ref(false)
const addDataCleanVisible = ref(false)
const editDataCleanVisible = ref(false)
const dataCleanList = ref([])
const ref_addDataCleanForm = ref()
const ref_editDataCleanForm = ref()
const router = useRouter()
let selectedMenuIndex = ''
// computed
// mapping
const rules = reactive(
{}
)
const userNameIdMap = reactive({})
const imagePackageMap = reactive({})
const addDataCleanForm = reactive(
{
packId: '',
name: '',
}
)
const editDataCleanForm = reactive(
{
packId: '',
name: '',
}
)
// function
const onPageNumChange = function(num) {
pageNum.value = num
getDataCleanList()
}
const onPageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
getDataCleanList()
}
const confirmAddDataClean = function() {
ref_addDataCleanForm.value.validate(
(isValid) => {
if (isValid)
{
addDataCleanVisible.value = false
const rawData = toRaw(addDataCleanForm)
const data = filterEmptyValueInObject(rawData)
classInsideCleanApi.addDataClean(data).then(
(r) => {
const message = r.msg
ElMessage(`${message}`)
getDataCleanList()
}
)
}
}
)
}
const editDataClean = function(row) {
editDataCleanVisible.value = true
editDataCleanForm.id = row.id
editDataCleanForm.name = row.name
editDataCleanForm.managerId = row.managerId
editDataCleanForm.description = row.description
}
const confirmEditDataClean = function() {
ref_editDataCleanForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(editDataCleanForm)
const data = filterEmptyValueInObject(
{
name: rawData.name,
managerId: rawData.managerId,
description: rawData.description,
}
)
classInsideCleanApi.editDataClean(rawData.id, data).then(
(r) => {
const message = r.msg
getDataCleanList()
ElMessage(`${message}`)
}
)
editDataCleanVisible.value = false
}
}
)
}
const confirmDeleteDataClean = function(id) {
ElMessageBox.confirm(
"删除后此数据清洗相关数据全部都会消失,你确定要删除吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(
() => {
classInsideCleanApi.deleteDataClean(id).then(
(r) => {
const message = r.msg
getDataCleanList()
ElMessage(`${message}`)
}
)
}
)
}
const addDataClean = function() {
resetForm(addDataCleanForm)
addDataCleanVisible.value = true
}
const getDataCleanList = function() {
isLoading.value = true
classInsideCleanApi.getClassInsideCleanList({
packId: packId,
status: selectedMenuIndex,
pageNum: pageNum.value,
pageSize: pageSize.value,
}).then(
({data}) => {
isLoading.value = false
dataCleanList.value = data.list
total.value = data.total
}
)
}
const getStatusTitle = function(status) {
switch (status)
{
case 0:
{
return '未处理'
}
case 1:
{
return '已处理'
}
case 2:
{
return '处理中'
}
default:
{
break
}
}
}
const getTypeTitle = function(status) {
switch (status)
{
case 1:
{
return '类内清洗'
}
case 2:
{
return '类间清洗'
}
{
break
}
}
}
const gotoHandle = function(row) {
router.push(
{
path: '/ClassInsideJudgePerson',
query: {
personId: row.personId,
packId: row.packId,
name: name,
packName: packName,
}
}
)
}
const onMenuSelect = function(index) {
selectedMenuIndex = index
getDataCleanList()
}
const getSameTitle = function(same) {
switch (same)
{
case 0:
{
return '不是'
}
case 1:
{
return '是'
}
default:
{
break
}
}
}
// const goBack = function() {
// router.push(
// {
// path: '/DataClean/DataClean',
// }
// )
// }
const initialize = function() {
getDataCleanList()
getUserNameIdMap(userNameIdMap)
getImagePackageMap(imagePackageMap)
}
initialize()
return {
// scalar
name,
packName,
pageNum,
pageSize,
total,
isLoading,
dataCleanList,
ref_addDataCleanForm,
ref_editDataCleanForm,
addDataCleanVisible,
editDataCleanVisible,
// mapping
userNameIdMap,
imagePackageMap,
addDataCleanForm,
editDataCleanForm,
rules,
// function
onPageNumChange,
onPageSizeChange,
addDataClean,
editDataClean,
confirmEditDataClean,
confirmAddDataClean,
confirmDeleteDataClean,
gotoHandle,
getStatusTitle,
getTypeTitle,
getSameTitle,
onMenuSelect,
goBack,
}
},
}
</script>
<style lang="less" scoped>
@import "./ClassInsideClean.less";
</style>
.Labeling {
background: white;
}
.el-main {
margin: 0;
padding: 0;
}
.el-header {
padding: 0;
}
.isSelected {
border: 2px solid #4487f7 !important;
}
.isFolderSelected {
background: aquamarine;
}
.isSelected:after {
bottom: 0px;
right: 0px;
content: "";
position: absolute;
width: 0;
height: 0;
border-bottom: 42px solid #4487f7;
border-left: 42px solid transparent;
}
.isSelected:before {
content: '';
position: absolute;
width: 14px;
height: 8px;
background: transparent;
bottom: 12px;
right: 5px;
border: 2px solid white;
border-top: none;
border-right: none;
-webkit-transform: rotate(-55deg);
-ms-transform: rotate(-55deg);
transform: rotate(-55deg);
z-index: 9;
}
.single-image-parent {
//display: inline-block;
position: relative;
border: 2px solid white;
text-align: center;
}
.single-image {
height: 300px;
width: 100%;
cursor: pointer;
}
.right-image-folder-list {
//border-radius: 10px;
margin: 10px 0;
}
<template>
<el-container>
<el-header height="auto">
<div style="display: flex; justify-content:flex-end">
<el-button @click="goBack">返回上一页</el-button>
</div>
<el-row>
<el-col :span="12">
<span style="font-size: 20px">ID:{{ personId }}</span>
</el-col>
<el-col :span="12">
<span style="font-size: 20px">异常图片</span>
</el-col>
</el-row>
</el-header>
<el-main>
<el-container>
<el-aside :width="'50%'" style="border-right: red 1px solid">
<!-- <VirtualList-->
<!-- :dataList="leftPagedTableData"-->
<!-- :key="leftPagedTableData"-->
<!-- @imageClick="selectImage"-->
<!-- >-->
<!-- </VirtualList>-->
<el-row v-for="row in leftPagedTableData">
<el-col :span="8" v-for="item in row" @click="selectImage(item.unid)">
<div v-bind:class="{ 'isSelected': item.isSelected}"
class="single-image-parent flex-vertical-center">
<el-image :src="getImageUrl(item.picId)"
:fit="'contain'"
class="single-image">
</el-image>
</div>
</el-col>
</el-row>
</el-aside>
<el-main>
<!-- <VirtualList-->
<!-- :dataList="rightPagedTableData"-->
<!-- :key="rightPagedTableData"-->
<!-- @imageClick="selectImage"-->
<!-- >-->
<!-- </VirtualList>-->
<el-row v-for="row in rightPagedTableData">
<el-col :span="8" v-for="item in row" @click="selectImage(item.unid)">
<div v-bind:class="{ 'isSelected': item.isSelected}"
class="single-image-parent flex-vertical-center">
<el-image :src="getImageUrl(item.picId)"
:fit="'contain'"
class="single-image">
</el-image>
</div>
</el-col>
</el-row>
</el-main>
</el-container>
</el-main>
<el-footer>
<div style="display: flex; justify-content:flex-end;height: 100%" class="flex-vertical-center">
<el-button type="primary" @click="onlySplit">只拆分(A)</el-button>
<el-button type="primary" @click="split">拆分并完成(D)</el-button>
</div>
</el-footer>
</el-container>
</template>
<script>
import {useRoute, useRouter} from 'vue-router'
import {
getPagedList,
getImageUrl,
} from '@/PublicUtil/PublicUtil'
import {computed, onBeforeUnmount, reactive, ref} from 'vue'
import labelingApi from '@/views/DataLabel/Labeling/LabelingApi'
import {ElMessage} from 'element-plus'
import classInsideCleanApi from '@/views/ClassInsideClean/ClassInsideClean'
import VirtualList from './VirtualList/VirtualList'
export default {
components: {
VirtualList,
},
setup() {
const name = useRoute().query.name
const packName = useRoute().query.packName
const personId = useRoute().query.personId
const packId = useRoute().query.packId
const leftPeopleImageList = ref([])
const rightPeopleImageList = ref([])
let leftSelectedImageUnidList = []
let rightSelectedImageUnidList = []
let allSelectedImageIdList = []
const router = useRouter()
const leftPagedTableData = computed(
() => {
return getPagedList(leftPeopleImageList.value, 3)
}
)
const rightPagedTableData = computed(
() => {
return getPagedList(rightPeopleImageList.value, 3)
}
)
const getLeftPeopleImageList = function() {
labelingApi.getPeopleImageList(packId, personId).then(
(r) => {
leftPeopleImageList.value = r.data
for (const peopleImage of leftPeopleImageList.value)
{
peopleImage['isSelected'] = false
}
}
)
}
const getRightPeopleImageList = function() {
const data = {
personId: personId,
packId: packId,
}
classInsideCleanApi.getCleanInsideResult(data).then(
({data}) => {
rightPeopleImageList.value = data
for (const peopleImage of rightPeopleImageList.value)
{
peopleImage['isSelected'] = false
}
}
)
}
const onlySplit = function() {
const data = {
personId: personId,
packId: packId,
picIds: allSelectedImageIdList.toString(),
}
classInsideCleanApi.split(data).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
window.location.reload()
}
)
}
const split = function() {
const data = {
personId: personId,
packId: packId,
picIds: allSelectedImageIdList.toString(),
}
classInsideCleanApi.split(data).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
if (r.code === 200)
{
classInsideCleanApi.getCleanInsideResult({packId: packId}).then(
({data}) => {
router.push(
{
path: '/ClassInsideJudgePerson',
query: {
personId: data[0].personUnid,
packId: packId,
}
}
)
}
)
}
}
)
}
const changeSelectedImageIdList = function(item, position) {
item['isSelected'] = !item['isSelected']
if (item['isSelected'] === true)
{
if (position === 'left')
{
leftSelectedImageUnidList.push(item.unid)
}
else
{
rightSelectedImageUnidList.push(item.unid)
}
}
else
{
if (position === 'left')
{
leftSelectedImageUnidList.splice(leftSelectedImageUnidList.indexOf(item.unid), 1)
}
else
{
rightSelectedImageUnidList.splice(rightSelectedImageUnidList.indexOf(item.unid), 1)
}
}
allSelectedImageIdList = leftSelectedImageUnidList.concat(rightSelectedImageUnidList)
allSelectedImageIdList = [...new Set(allSelectedImageIdList)]
}
const selectImage = function(unid) {
for (let row of leftPagedTableData.value)
{
for (let item of row)
{
if (item.unid === unid)
{
changeSelectedImageIdList(item, 'left')
}
}
}
for (let row of rightPagedTableData.value)
{
for (let item of row)
{
if (item.unid === unid)
{
changeSelectedImageIdList(item, 'right')
}
}
}
}
const goBack = function() {
router.push(
{
path: '/ClassInsideClean',
query: {
packId: packId,
name: name,
packName: packName,
}
}
)
}
const addShortcutKey = function(event) {
if (event.code === 'KeyA')
{
onlySplit()
}
if (event.code === 'KeyD')
{
split()
}
}
onBeforeUnmount(
() => {
document.removeEventListener('keydown', addShortcutKey)
}
)
const initialize = function() {
getLeftPeopleImageList()
getRightPeopleImageList()
document.addEventListener('keydown', addShortcutKey)
}
initialize()
return {
// scalar
personId,
// sequence
leftPagedTableData,
rightPagedTableData,
// mapping
// function
onlySplit,
split,
selectImage,
getImageUrl,
goBack,
}
}
}
</script>
<style lang="less" scoped>
@import "./ClassInsideJudgePerson.less";
</style>
.container {
margin: 0;
padding: 0;
overflow: auto;
}
.clearfix::after {
content: '';
display: block;
clear: both;
}
.empty {
float: left;
}
.single-image-parent {
position: relative;
border: 2px solid white;
text-align: center;
}
.single-image {
height: 300px;
width: 100%;
cursor: pointer;
}
.el-row {
height: 326px !important;
}
.isSelected {
border: 2px solid #4487f7 !important;
}
.isSelected:after {
bottom: 0px;
right: 0px;
content: "";
position: absolute;
width: 0;
height: 0;
border-bottom: 42px solid #4487f7;
border-left: 42px solid transparent;
}
.isSelected:before {
content: '';
position: absolute;
width: 14px;
height: 8px;
background: transparent;
bottom: 12px;
right: 5px;
border: 2px solid white;
border-top: none;
border-right: none;
-webkit-transform: rotate(-55deg);
-ms-transform: rotate(-55deg);
transform: rotate(-55deg);
z-index: 9;
}
<template>
<div class="container clearfix" ref="containerRef" style="height: 100%">
<div class="empty" :style="{ height: emptyHeight }"></div>
<div :style="{ transform: `translateY(${translateY})` }">
<el-row v-for="row in showedList">
<el-col :span="8" v-for="item in row" @click="selectImage(item.unid)">
<div v-bind:class="{ 'isSelected': item.isSelected}"
class="single-image-parent flex-vertical-center"
@contextmenu.prevent=""
@click.right="previewImage(getImageUrl(item.picId))">
<el-image :src="getImageUrl(item.picId)"
:fit="'contain'"
class="single-image">
</el-image>
</div>
<div>
{{ item.createTime }} {{ getDirectionTitle(item.direction) }}
</div>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import {computed, onMounted, ref} from 'vue'
import {getImageUrl, getPagedList, previewImage} from '@/PublicUtil/PublicUtil'
export default {
props: {
dataList: {
default: []
},
},
setup(props, {emit}) {
const dataList = props.dataList
const containerRef = ref()
const itemHeight = 326
const start = ref(0)
const translateY = ref(0)
const showedList = computed(
() => {
return dataList.slice(start.value, start.value + 3)
}
)
const emptyHeight = itemHeight * (dataList.length + 1)
const getDirectionTitle = function(v) {
switch (v)
{
case 1:
{
return '进'
}
case -1:
{
return '出'
}
default:
{
break
}
}
}
const selectImage = function(unid) {
emit('imageClick', unid)
}
onMounted(
() => {
containerRef.value.addEventListener(
'scroll',
(event) => {
const {scrollTop} = event.target
start.value = Math.floor(scrollTop / itemHeight)
translateY.value = scrollTop + 'px'
}
)
}
)
return {
containerRef,
translateY,
itemHeight: itemHeight + 'px',
emptyHeight: emptyHeight + 'px',
// sequence
showedList,
// function
selectImage,
getDirectionTitle,
getImageUrl,
previewImage,
}
}
}
</script>
<style lang="less" scoped>
@import "./VirtualList";
</style>
<template>
<el-container class="DataClean">
<el-header height="50px">
<div>
<span class="title-text">清洗管理</span>
</div>
</el-header>
<el-main>
<el-button type="primary" @click="addDataClean">新建</el-button>
<el-button type="primary" @click="refreshTable">刷新列表</el-button>
<el-table :data="dataCleanList" v-loading="isLoading">
<el-table-column prop="name" label="名称" align="center"></el-table-column>
<el-table-column prop="cleanType" label="清洗类型" align="center">
<template #default="scope">
{{ getTypeTitle(scope.row.cleanType) }}
</template>
</el-table-column>
<el-table-column prop="status" label="清洗状态" align="center">
<template #default="scope">
{{ getStatusTitle(scope.row.status, scope.row.progress) }}
</template>
</el-table-column>
<el-table-column prop="packName" label="批次名" align="center"></el-table-column>
<el-table-column prop="updateTime" label="修改时间" align="center"></el-table-column>
<el-table-column prop="score" label="阈值" align="center"></el-table-column>
<el-table-column prop="percent" label="占比" align="center"></el-table-column>
<el-table-column prop="maxNum" label="抽取数量" align="center">
<template #default="scope">
{{ scope.row.cleanType === 2 ? scope.row.maxNum : '' }}
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" align="center" width="350">
<template #default="scope">
<el-button @click="classInsideClean(scope.row.id)" v-if="[1, 5].includes(scope.row.status)" type="text" v-loading="isButtonLoading">类内清洗</el-button>
<el-button @click="classAmongClean(scope.row.id)" v-if="[1, 5].includes(scope.row.status)" type="text" v-loading="isButtonLoading">类间清洗</el-button>
<el-button @click="gotoHandle(scope.row)" v-if="[3].includes(scope.row.status)" type="text" v-loading="isButtonLoading">进入处理</el-button>
<el-button @click="completeClean(scope.row.id)" v-if="[3].includes(scope.row.status)" type="text" v-loading="isButtonLoading">完成清洗</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination @current-change="onPageNumChange"
@size-change="onPageSizeChange"
:current-page="pageNum"
:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 40, 80]"
layout="total, sizes, prev, pager, next, jumper"
style="text-align:center"
>
</el-pagination>
<el-drawer title="新建数据清洗" v-model="addDataCleanVisible" :destroy-on-close="true" :direction="'rtl'">
<div class="dataClean-form">
<el-form :model="addDataCleanForm" :rules="rules" ref="ref_addDataCleanForm">
<el-form-item label="批次:" :label-width="'120px'">
<el-select v-model="addDataCleanForm.packId" style="width: 100%">
<el-option v-for="(name, value) in imagePackageMap" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="任务名:" :label-width="'120px'">
<el-input v-model.trim="addDataCleanForm.name"></el-input>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="addDataCleanVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmAddDataClean">确 定</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
<el-dialog title="类内清洗" v-model="isClassInsideCleanVisible" width="30%" :destroy-on-close="true" center>
<el-form :model="classInsideCleanForm">
<el-form-item label="阈值:">
<el-input-number v-model="classInsideCleanForm.score" :step="0.1" :min="0" :max="1" style="width: 100%"/>
<div>范围:0-1之间,可为小数</div>
</el-form-item>
<el-form-item label="比例:">
<el-input-number v-model="classInsideCleanForm.percent" :step="0.1" :min="0" :max="1" style="width: 100%"/>
<div>范围:0-1之间,可为小数</div>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="isClassInsideCleanVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmClassInsideClean">确 定</el-button>
</el-form-item>
</el-form>
</el-dialog>
<el-dialog title="类间清洗" v-model="isClassAmongCleanVisible" width="30%" :destroy-on-close="true" center>
<el-form :model="classAmongCleanForm">
<el-form-item label="阈值:" :label-width="'140px'">
<el-input-number v-model="classAmongCleanForm.score" :step="0.1" :min="0" :max="1" style="width: 100%"/>
<div>范围:0.7-1之间,可为小数</div>
</el-form-item>
<el-form-item label="比例:" :label-width="'140px'">
<el-input-number v-model="classAmongCleanForm.percent" :step="0.1" :min="0" :max="1" style="width: 100%"/>
<div>范围:0-1之间,可为小数</div>
</el-form-item>
<el-form-item label="抽取每人图片数量:" :label-width="'140px'">
<el-input-number v-model="classAmongCleanForm.maxNum" :step="1" :min="0" style="width: 100%"/>
<div>数量越小,清洗越快</div>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="isClassAmongCleanVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmClassAmongClean">确 定</el-button>
</el-form-item>
</el-form>
</el-dialog>
</el-main>
</el-container>
</template>
<script>
import {computed, onMounted, reactive, ref, toRaw, toRefs, watch} from "vue"
import {
filterEmptyValueInObject,
resetForm
} from "@/PublicUtil/PublicUtil"
import dataCleanApi from './DataCleanApi'
import {ElMessageBox} from 'element-plus'
import {ElMessage} from 'element-plus'
import {getImagePackageMap, getUserNameIdMap} from '@/Request/DictionaryRequest'
import router from '@/router'
import {useRouter} from 'vue-router'
import {isEmptyValue} from '@/PublicUtil/Judgment'
import imagePackageApi from '@/views/DataLabel/ImagePackage/ImagePackageApi'
export default {
setup() {
// scalar
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref()
const isLoading = ref(false)
const addDataCleanVisible = ref(false)
const editDataCleanVisible = ref(false)
const isButtonLoading = ref(false)
const isClassInsideCleanVisible = ref(false)
const isClassAmongCleanVisible = ref(false)
const dataCleanList = ref([])
const ref_addDataCleanForm = ref()
const ref_editDataCleanForm = ref()
const router = useRouter()
// computed
// mapping
const rules = reactive(
{}
)
const userNameIdMap = reactive({})
const imagePackageMap = reactive({})
const addDataCleanForm = reactive(
{
packId: '',
name: '',
}
)
const editDataCleanForm = reactive(
{
packId: '',
name: '',
}
)
const classInsideCleanForm = reactive(
{
taskId: '',
score: '',
percent: '',
}
)
const classAmongCleanForm = reactive(
{
taskId: '',
score: '',
percent: '',
maxNum: '',
}
)
// function
const onPageNumChange = function(num) {
pageNum.value = num
getDataCleanList()
}
const onPageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
getDataCleanList()
}
const confirmAddDataClean = function() {
ref_addDataCleanForm.value.validate(
(isValid) => {
if (isValid)
{
addDataCleanVisible.value = false
const rawData = toRaw(addDataCleanForm)
const data = filterEmptyValueInObject(rawData)
dataCleanApi.addDataClean(data).then(
(r) => {
const message = r.msg
ElMessage(`${message}`)
getDataCleanList()
}
)
}
}
)
}
const editDataClean = function(row) {
editDataCleanVisible.value = true
editDataCleanForm.id = row.id
editDataCleanForm.name = row.name
editDataCleanForm.managerId = row.managerId
editDataCleanForm.description = row.description
}
const confirmEditDataClean = function() {
ref_editDataCleanForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(editDataCleanForm)
const data = filterEmptyValueInObject(
{
name: rawData.name,
managerId: rawData.managerId,
description: rawData.description,
}
)
dataCleanApi.editDataClean(rawData.id, data).then(
(r) => {
const message = r.msg
getDataCleanList()
ElMessage(`${message}`)
}
)
editDataCleanVisible.value = false
}
}
)
}
const addDataClean = function() {
resetForm(addDataCleanForm)
addDataCleanVisible.value = true
}
const getDataCleanList = function() {
isLoading.value = true
dataCleanApi.getDataCleanList({
pageNum: pageNum.value,
pageSize: pageSize.value,
}).then(
({data}) => {
isLoading.value = false
dataCleanList.value = data.list
total.value = data.total
}
)
}
const getStatusTitle = function(status, progress) {
if (isEmptyValue(progress))
{
progress = ''
}
switch (status)
{
case 1:
{
return '待清洗' + progress
}
case 2:
{
return '清洗中' + progress
}
case 3:
{
return '人工处理中' + progress
}
case 4:
{
return '合并中' + progress
}
case 5:
{
return '清洗完成' + progress
}
default:
{
break
}
}
}
const classInsideClean = function(id) {
classInsideCleanForm.taskId = id
isClassInsideCleanVisible.value = true
}
const classAmongClean = function(id) {
classAmongCleanForm.taskId = id
isClassAmongCleanVisible.value = true
}
const confirmClassInsideClean = function() {
isClassInsideCleanVisible.value = false
isButtonLoading.value = true
const data = filterEmptyValueInObject(toRaw(classInsideCleanForm))
dataCleanApi.cleanInsideClean(data).then(
(r) => {
isButtonLoading.value = false
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
getDataCleanList()
}
)
}
const confirmClassAmongClean = function() {
isClassAmongCleanVisible.value = false
isButtonLoading.value = true
const data = filterEmptyValueInObject(toRaw(classAmongCleanForm))
dataCleanApi.cleanAmongClean(data).then(
(r) => {
isButtonLoading.value = false
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
getDataCleanList()
}
)
}
const getTypeTitle = function(cleanType) {
switch (cleanType)
{
case 1:
{
return '类内清洗'
}
case 2:
{
return '类间清洗'
}
{
break
}
}
}
const gotoHandle = function(row) {
switch (row.cleanType)
{
case 1:
{
router.push(
{
path: '/ClassInsideClean',
query: {
packId: row.packId,
name: row.name,
packName: row.packName,
}
}
)
break
}
case 2:
{
router.push(
{
path: '/ClassAmongClean',
query: {
packId: row.packId,
name: row.name,
packName: row.packName,
}
}
)
break
}
default:
{
break
}
}
}
const completeClean = function(id) {
isButtonLoading.value = true
dataCleanApi.completeClean(id).then(
(r) => {
isButtonLoading.value = false
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
getDataCleanList()
}
)
}
const getImagePackageMap = function() {
dataCleanApi.getImagePackageMap().then(
({data}) => {
for (const item of data)
{
imagePackageMap[item.id] = item.name
}
}
)
}
const refreshTable = function() {
getDataCleanList()
}
const initialize = function() {
getDataCleanList()
getImagePackageMap()
getUserNameIdMap(userNameIdMap)
}
initialize()
return {
// scalar
pageNum,
pageSize,
total,
isLoading,
dataCleanList,
ref_addDataCleanForm,
ref_editDataCleanForm,
addDataCleanVisible,
editDataCleanVisible,
isButtonLoading,
isClassInsideCleanVisible,
isClassAmongCleanVisible,
// mapping
userNameIdMap,
imagePackageMap,
addDataCleanForm,
editDataCleanForm,
rules,
classInsideCleanForm,
classAmongCleanForm,
// function
onPageNumChange,
onPageSizeChange,
addDataClean,
editDataClean,
confirmEditDataClean,
confirmAddDataClean,
gotoHandle,
getStatusTitle,
getTypeTitle,
classInsideClean,
classAmongClean,
completeClean,
refreshTable,
confirmClassInsideClean,
confirmClassAmongClean,
}
},
}
</script>
<style lang="less" scoped>
@import "./DataClean.less";
</style>
import {axiosInstance2} from '@/Request/PublicAxiosInstance'
import {filterEmptyValueInObject, getFormDataByObject,} from "@/PublicUtil/PublicUtil"
import {getImagePackageMap} from '@/Request/DictionaryRequest'
class DataCleanApi {
getDataCleanList(data) {
return axiosInstance2.request(
{
method: 'GET',
url: '/pack-clean/list',
params: {
pageNum: data.pageNum,
pageSize: data.pageSize,
}
}
)
}
addDataClean(data) {
return axiosInstance2.request(
{
method: 'POST',
url: '/pack-clean',
params: filterEmptyValueInObject(
{
packId: data.packId,
name: data.name,
}
)
}
)
}
cleanInsideClean(data) {
return axiosInstance2.request(
{
method: 'POST',
url: `/cleaning/clean1`,
data: getFormDataByObject(
{
taskId: data.taskId,
score: data.score,
percent: data.percent,
}
)
}
)
}
cleanAmongClean(data) {
return axiosInstance2.request(
{
method: 'POST',
url: `/cleaning/clean2`,
data: getFormDataByObject(
{
taskId: data.taskId,
score: data.score,
percent: data.percent,
maxNum: data.maxNum,
}
)
}
)
}
completeClean(taskId) {
return axiosInstance2.request(
{
method: 'POST',
url: `/cleaning/completeClean`,
data: getFormDataByObject(
{
taskId: taskId
}
)
}
)
}
getImagePackageMap() {
return axiosInstance2.request(
{
method: 'GET',
url: `/pack-clean/listPacks`,
}
)
}
}
const dataCleanApi = new DataCleanApi()
export default dataCleanApi
<template>
<el-container class="DataClean">
<el-header height="50px">
<div>
<span class="title-text">数据清洗</span>
</div>
</el-header>
<el-main>
<!-- <el-button type="primary" @click="addDataClean">新建</el-button>-->
<el-button type="primary" @click="refreshTable">刷新列表</el-button>
<el-table :data="dataCleanList" v-loading="isLoading">
<el-table-column prop="name" label="名称" align="center"></el-table-column>
<el-table-column prop="cleanType" label="清洗类型" align="center">
<template #default="scope">
{{ getTypeTitle(scope.row.cleanType) }}
</template>
</el-table-column>
<el-table-column prop="status" label="清洗状态" align="center">
<template #default="scope">
{{ getStatusTitle(scope.row.status, scope.row.progress) }}
</template>
</el-table-column>
<el-table-column prop="packName" label="批次名" align="center"></el-table-column>
<el-table-column prop="updateTime" label="修改时间" align="center"></el-table-column>
<el-table-column prop="score" label="阈值" align="center"></el-table-column>
<el-table-column prop="percent" label="占比" align="center"></el-table-column>
<el-table-column prop="maxNum" label="抽取数量" align="center">
<template #default="scope">
{{ scope.row.cleanType === 2 ? scope.row.maxNum : '' }}
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" align="center" width="350">
<template #default="scope">
<!-- <el-button @click="clean(scope.row.id, '类内清洗')" v-if="[1, 5].includes(scope.row.status)" type="text" v-loading="isButtonLoading">类内清洗</el-button>-->
<!-- <el-button @click="clean(scope.row.id, '类间清洗')" v-if="[1, 5].includes(scope.row.status)" type="text" v-loading="isButtonLoading">类间清洗</el-button>-->
<el-button @click="gotoHandle(scope.row)" v-if="[3].includes(scope.row.status)" type="text" v-loading="isButtonLoading">进入处理</el-button>
<!-- <el-button @click="completeClean(scope.row.id)" v-if="[3].includes(scope.row.status)" type="text" v-loading="isButtonLoading">完成清洗</el-button>-->
</template>
</el-table-column>
</el-table>
<el-pagination @current-change="onPageNumChange"
@size-change="onPageSizeChange"
:current-page="pageNum"
:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 40, 80]"
layout="total, sizes, prev, pager, next, jumper"
style="text-align:center"
>
</el-pagination>
<el-drawer title="新建数据清洗" v-model="addDataCleanVisible" :destroy-on-close="true" :direction="'rtl'">
<div class="dataClean-form">
<el-form :model="addDataCleanForm" :rules="rules" ref="ref_addDataCleanForm">
<el-form-item label="批次:" :label-width="'120px'">
<el-select v-model="addDataCleanForm.packId" style="width: 100%">
<el-option v-for="(name, value) in imagePackageMap" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="任务名:" :label-width="'120px'">
<el-input v-model.trim="addDataCleanForm.name"></el-input>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="addDataCleanVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmAddDataClean">确 定</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
</el-main>
</el-container>
</template>
<script>
import {computed, onMounted, reactive, ref, toRaw, toRefs, watch} from "vue"
import {
filterEmptyValueInObject,
resetForm
} from "@/PublicUtil/PublicUtil"
import dataCleanApi from './DataCleanApi'
import {ElMessageBox} from 'element-plus'
import {ElMessage} from 'element-plus'
import {getImagePackageMap, getUserNameIdMap} from '@/Request/DictionaryRequest'
import router from '@/router'
import {useRouter} from 'vue-router'
import {isEmptyValue} from '@/PublicUtil/Judgment'
import imagePackageApi from '@/views/DataLabel/ImagePackage/ImagePackageApi'
export default {
setup() {
// scalar
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref()
const isLoading = ref(false)
const addDataCleanVisible = ref(false)
const editDataCleanVisible = ref(false)
const isButtonLoading = ref(false)
const dataCleanList = ref([])
const ref_addDataCleanForm = ref()
const ref_editDataCleanForm = ref()
const router = useRouter()
// computed
// mapping
const rules = reactive(
{}
)
const userNameIdMap = reactive({})
const imagePackageMap = reactive({})
const addDataCleanForm = reactive(
{
packId: '',
name: '',
}
)
const editDataCleanForm = reactive(
{
packId: '',
name: '',
}
)
// function
const onPageNumChange = function(num) {
pageNum.value = num
getDataCleanList()
}
const onPageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
getDataCleanList()
}
const confirmAddDataClean = function() {
ref_addDataCleanForm.value.validate(
(isValid) => {
if (isValid)
{
addDataCleanVisible.value = false
const rawData = toRaw(addDataCleanForm)
const data = filterEmptyValueInObject(rawData)
dataCleanApi.addDataClean(data).then(
(r) => {
const message = r.msg
ElMessage(`${message}`)
getDataCleanList()
}
)
}
}
)
}
const editDataClean = function(row) {
editDataCleanVisible.value = true
editDataCleanForm.id = row.id
editDataCleanForm.name = row.name
editDataCleanForm.managerId = row.managerId
editDataCleanForm.description = row.description
}
const confirmEditDataClean = function() {
ref_editDataCleanForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(editDataCleanForm)
const data = filterEmptyValueInObject(
{
name: rawData.name,
managerId: rawData.managerId,
description: rawData.description,
}
)
dataCleanApi.editDataClean(rawData.id, data).then(
(r) => {
const message = r.msg
getDataCleanList()
ElMessage(`${message}`)
}
)
editDataCleanVisible.value = false
}
}
)
}
const addDataClean = function() {
resetForm(addDataCleanForm)
addDataCleanVisible.value = true
}
const getDataCleanList = function() {
isLoading.value = true
dataCleanApi.getDataCleanList({
pageNum: pageNum.value,
pageSize: pageSize.value,
}).then(
({data}) => {
isLoading.value = false
dataCleanList.value = data.list
total.value = data.total
}
)
}
const getStatusTitle = function(status, progress) {
if (isEmptyValue(progress))
{
progress = ''
}
switch (status)
{
case 1:
{
return '待清洗' + progress
}
case 2:
{
return '清洗中' + progress
}
case 3:
{
return '人工处理中' + progress
}
case 4:
{
return '合并中' + progress
}
case 5:
{
return '清洗完成' + progress
}
default:
{
break
}
}
}
const clean = function(id, typeText) {
isButtonLoading.value = true
switch (typeText)
{
case '类内清洗':
{
dataCleanApi.clean(1, id).then(
(r) => {
isButtonLoading.value = false
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
getDataCleanList()
}
)
break
}
case '类间清洗':
{
dataCleanApi.clean(2, id).then(
(r) => {
isButtonLoading.value = false
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
getDataCleanList()
}
)
break
}
default:
{
isButtonLoading.value = false
break
}
}
}
const getTypeTitle = function(cleanType) {
switch (cleanType)
{
case 1:
{
return '类内清洗'
}
case 2:
{
return '类间清洗'
}
{
break
}
}
}
const gotoHandle = function(row) {
switch (row.cleanType)
{
case 1:
{
router.push(
{
path: '/ClassInsideClean',
query: {
packId: row.packId,
name: row.name,
packName: row.packName,
}
}
)
break
}
case 2:
{
router.push(
{
path: '/ClassAmongClean',
query: {
packId: row.packId,
name: row.name,
packName: row.packName,
}
}
)
break
}
default:
{
break
}
}
}
const completeClean = function(id) {
isButtonLoading.value = true
dataCleanApi.completeClean(id).then(
(r) => {
isButtonLoading.value = false
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
getDataCleanList()
}
)
}
const getImagePackageMap = function() {
dataCleanApi.getImagePackageMap().then(
({data}) => {
for (const item of data)
{
imagePackageMap[item.id] = item.name
}
}
)
}
const refreshTable = function() {
getDataCleanList()
}
const initialize = function() {
getDataCleanList()
getImagePackageMap()
getUserNameIdMap(userNameIdMap)
}
initialize()
return {
// scalar
pageNum,
pageSize,
total,
isLoading,
dataCleanList,
ref_addDataCleanForm,
ref_editDataCleanForm,
addDataCleanVisible,
editDataCleanVisible,
isButtonLoading,
// mapping
userNameIdMap,
imagePackageMap,
addDataCleanForm,
editDataCleanForm,
rules,
// function
onPageNumChange,
onPageSizeChange,
addDataClean,
editDataClean,
confirmEditDataClean,
confirmAddDataClean,
gotoHandle,
getStatusTitle,
getTypeTitle,
clean,
completeClean,
refreshTable,
}
},
}
</script>
<style lang="less" scoped>
@import "./DataClean.less";
</style>
import {axiosInstance2} from '@/Request/PublicAxiosInstance'
import {filterEmptyValueInObject, getFormDataByObject} from "@/PublicUtil/PublicUtil"
import {getImagePackageMap} from '@/Request/DictionaryRequest'
class DataCleanApi {
getDataCleanList(data) {
return axiosInstance2.request(
{
method: 'GET',
url: '/pack-clean/list',
params: {
pageNum: data.pageNum,
pageSize: data.pageSize,
}
}
)
}
addDataClean(data) {
return axiosInstance2.request(
{
method: 'POST',
url: '/pack-clean',
params: filterEmptyValueInObject(
{
packId: data.packId,
name: data.name,
}
)
}
)
}
clean(cleanType, taskId) {
return axiosInstance2.request(
{
method: 'POST',
url: `/cleaning/clean${cleanType}`,
data: getFormDataByObject(
{
taskId: taskId
}
)
}
)
}
completeClean(taskId) {
return axiosInstance2.request(
{
method: 'POST',
url: `/cleaning/completeClean`,
data: getFormDataByObject(
{
taskId: taskId
}
)
}
)
}
getImagePackageMap() {
return axiosInstance2.request(
{
method: 'GET',
url: `/pack-clean/listPacks`,
}
)
}
}
const dataCleanApi = new DataCleanApi()
export default dataCleanApi
.ImagePackage {
background: white;
.image-package {
background: white;
}
.name {
height: 100%;
font-size: 17px;
font-weight: bold;
font-family: PingFangSC-Medium, PingFang SC;
color: rgba(0, 0, 0, 0.8);
}
}
<template>
<a-layout class="ImagePackage">
<el-form :model="queryImagePackageForm" :inline="true" size="small">
<el-form-item label="公司:">
<el-select v-model="queryImagePackageForm.companyId" @change="onSelectCompanyInQuery" style="width: 100%">
<el-option v-for="(name, value) in companyMap" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="项目:">
<el-select v-model="queryImagePackageForm.projectId" style="width: 100%">
<el-option v-for="(value, name) in projectMapInQuery" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="图包:">-->
<!-- <el-select v-model="queryImagePackageForm.imagePackageId" style="width: 100%">-->
<!-- <el-option v-for="(value, key) in imagePackageMapInQuery" :label="value" :value="key"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item>
<el-button @click="confirmQueryImagePackage" type="primary">查询</el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-form>
<el-row v-for="(row, index) in pagedTableData" v-loading="isLoading">
<el-col :span="6" v-for="(item, index) in row" style="cursor: pointer;">
<div class="image-package">
<el-row @click="gotoPeopleLabel(item.id)">
<el-col :span="4">
<img :src="require('./image/imagePackage.svg')"/>
</el-col>
<el-col :span="20">
<div class="name">
<div class="flex-vertical-center flex-horizontal-center">
图包: {{ item?.name }}
</div>
<div class="flex-vertical-center flex-horizontal-center">
公司: {{ companyMap[item?.task?.accountId] }}
</div>
<div class="flex-vertical-center flex-horizontal-center">
项目: {{ item?.task?.name }}
</div>
</div>
</el-col>
</el-row>
<a-button v-if="isDownloadShowed" @click="downloadCompletedImages(item.id)" type="link">下载</a-button>
</div>
</el-col>
</el-row>
</a-layout>
</template>
<script>
import {computed, defineComponent, reactive, ref, toRaw, toRefs, watch} from 'vue'
import {useRouter} from 'vue-router'
import peopleLabelApi from '@/views/DataLabel/PeopleLabel/PeopleLabelApi'
import {cloneObject, getKeyByValueInObject} from '@/PublicUtil/PublicUtil'
import imagePackageApi from '@/views/DataLabel/ImagePackage/ImagePackageApi'
import Cookies from 'js-cookie'
import {getCompanyMap} from '@/Request/DictionaryRequest'
import projectApi from '@/views/Project/ProjectManagement/ProjectManagementApi'
export default defineComponent(
{
setup() {
const router = useRouter()
const peopleFolderList = ref([])
const imagePackageList = ref([])
const isLoading = ref(false)
const isDownloadShowed = ref(localStorage.getItem('currentUserType') === '0')
const pagedTableData = computed(
() => {
let baseArray = imagePackageList.value
let len = baseArray.length
let n = 4 //每行显示4个
let lineNum = len % n === 0 ? len / n : Math.floor((len / n) + 1)
let result = []
for (let i = 0; i < lineNum; i++)
{
// slice() 方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。且原始数组不会被修改。
let temp = baseArray.slice(i * n, i * n + n)
result.push(temp)
}
return result
}
)
// mapping
const queryImagePackageForm = reactive(
{
companyId: '',
projectId: '',
imagePackageId: '',
}
)
const companyMap = reactive({})
const projectMapInQuery = reactive({})
const imagePackageMapInQuery = reactive({})
const downloadCompletedImages = function(packId) {
window.open(
` ${window._baseUrl}/reid/downloadLabeledPicAsZip`
+
`?packId=${packId}&token=${Cookies.get('token')}`
)
}
const gotoPeopleLabel = function(packId) {
router.push(
{
path: '/DataLabel/PeopleLabel',
query: {
packId: packId,
pageNum: 1,
}
}
)
}
const reset = function() {
for (let key in queryImagePackageForm)
{
queryImagePackageForm[key] = ''
}
}
const getProjectMapByCompanyId = async function(companyId) {
const {data} = await projectApi.getProjectList(companyId)
let map = {}
for (const project of data)
{
map[project.name] = project.id
}
return map
}
//
// const getFloorMapByprojectId = function(projectId) {
// }
const onSelectCompanyInQuery = async function(companyId) {
queryImagePackageForm.projectId = ''
queryImagePackageForm.imagePackageId = ''
const map = await getProjectMapByCompanyId(parseInt(companyId))
cloneObject(projectMapInQuery, map)
}
// const onSelectProjectInQuery = function(projectId) {
// queryImagePackageForm.imagePackageId = ''
// cloneObject(imagePackageMapInQuery, getFloorMapByprojectId(parseInt(projectId)))
// }
const confirmQueryImagePackage = function() {
isLoading.value = true
const rawData = toRaw(queryImagePackageForm)
const data = {
companyId: rawData.companyId,
projectId: rawData.projectId,
}
imagePackageApi.getImagePackageList(data).then(
(r) => {
isLoading.value = false
imagePackageList.value = r.data
}
)
}
const initialize = function() {
confirmQueryImagePackage()
getCompanyMap(companyMap)
}
initialize()
return {
// scalar
isLoading,
isDownloadShowed,
// sequence
peopleFolderList,
pagedTableData,
// mapping
queryImagePackageForm,
companyMap,
projectMapInQuery,
imagePackageMapInQuery,
// function
reset,
onSelectCompanyInQuery,
// onSelectProjectInQuery,
gotoPeopleLabel,
downloadCompletedImages,
confirmQueryImagePackage,
getKeyByValueInObject,
}
},
}
)
</script>
<style lang="less" scoped>
@import "./ImagePackage.less";
</style>
import {axiosInstance} from "@/Request/PublicAxiosInstance"
import {filterEmptyValueInObject} from "@/PublicUtil/PublicUtil"
class ImagePackageApi {
getImagePackageList(data) {
return axiosInstance.request(
{
method: 'GET',
url: `/packs`,
params: filterEmptyValueInObject(
{
accountId: data?.companyId,
taskId: data?.projectId,
type: 1,
}
)
}
)
}
}
const imagePackageApi = new ImagePackageApi()
export default imagePackageApi
<?xml version="1.0" encoding="UTF-8"?>
<svg width="60px" height="60px" viewBox="0 0 60 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>wenjianjia</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1.1数据标注_人行标注" transform="translate(-336.000000, -259.000000)" fill-rule="nonzero">
<g id="文件夹1" transform="translate(312.000000, 218.000000)">
<g id="wenjianjia" transform="translate(24.000000, 41.000000)">
<path d="M0,30 C0,46.5685425 13.4314575,60 30,60 C46.5685425,60 60,46.5685425 60,30 C60,13.4314575 46.5685425,0 30,0 C13.4314575,0 0,13.4314575 0,30 Z" id="路径" fill="#6F9AFF" opacity="0.15072955"></path>
<g id="编组" transform="translate(15.000000, 18.000000)">
<path d="M27.1107989,6.385231 L12.5367594,6.385231 C11.7221508,6.38536458 10.9992431,5.86424184 10.7433631,5.09242471 L10.6299287,4.75960069 C10.2020168,3.47433429 8.99689379,2.60744721 7.63980047,2.60869565 L3.15347366,2.60869565 C1.41326149,2.60994376 0.00250167591,4.01684454 0,5.75354456 L0,20.8551524 C0.00250047866,22.591411 1.41257011,23.9981295 3.15233935,24 L27.1085303,24 C28.8482995,23.9981294 30.2583691,22.591411 30.2608696,20.8551524 L30.2608696,9.53460681 C30.2583705,7.79878957 28.8489908,6.39225327 27.1096646,6.38975926" id="路径" fill="#6F9AFF"></path>
<path d="M25.5546678,0.000567944867 L7.43673523,0.000567944867 C7.20640021,-0.00923103112 6.98925259,0.108368919 6.87117036,0.306859121 C6.75308814,0.505349323 6.75308814,0.752763455 6.87117036,0.951253656 C6.98925259,1.14974386 7.20640021,1.26734381 7.43673523,1.25754483 C9.32670802,1.25669534 11.004785,2.46932433 11.601388,4.26704849 L11.7142513,4.60646621 C11.8000054,4.86347742 12.0398243,5.03695174 12.310169,5.03752666 L26.8085782,5.03752666 C27.1795791,5.04216465 27.5483824,5.09541437 27.9056087,5.1959216 C28.0942468,5.24662743 28.2956815,5.20639846 28.4505319,5.0870938 C28.6053823,4.96778914 28.6959924,4.78301189 28.6956522,4.58723251 L28.6956522,3.15036426 C28.6937851,1.41467951 27.2906327,0.00809561432 25.5591823,0.00622491766" id="路径" fill="#4076F7"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<template>
<el-form :model="exportDataForm" :inline="true" size="small">
<el-form-item label="公司:">
<el-select v-model="exportDataForm.companyId" @change="onSelectCompanyInQuery">
<el-option v-for="(name, value) in companyMap" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="项目:">
<el-select v-model="exportDataForm.projectId" @change="onSelectProjectInQuery">
<el-option v-for="(value, name) in projectMapInQuery" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图包:">
<el-select v-model="exportDataForm.imagePackageId">
<el-option v-for="(value, name) in imagePackageMapInQuery" :label="name" :value="value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="日期:">
<el-date-picker v-model="exportDataForm.time" type="daterange"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button @click="exportData" :loading="isLoading" type="primary">导出数据</el-button>
</el-form-item>
</el-form>
</template>
<script>
import {computed, defineComponent, reactive, ref, toRaw, toRefs, watch} from 'vue'
import imagePackageApi from '@/views/DataLabel/ImagePackage/ImagePackageApi'
import {cloneObject, filterEmptyValueInObject, formatDate} from '@/PublicUtil/PublicUtil'
import Cookies from 'js-cookie'
import projectApi from '@/views/Project/ProjectManagement/ProjectManagementApi'
import {getCompanyMap} from '@/Request/DictionaryRequest'
export default defineComponent(
{
setup() {
// scalar
const isLoading = ref()
// sequence
const imagePackageList = ref([])
// mapping
const exportDataForm = reactive(
{
companyId: '',
projectId: '',
imagePackageId: '',
start: '',
end: '',
time: '',
}
)
const companyMap = reactive({})
const projectMapInQuery = reactive({})
const imagePackageMapInQuery = reactive({})
// function
const exportData = function() {
const rawData = toRaw(exportDataForm)
const data = filterEmptyValueInObject(
{
accountId: rawData.companyId,
taskId: rawData.projectId,
packId: rawData.imagePackageId,
start: formatDate(rawData.time[0]),
end: formatDate(rawData.time[1]),
}
)
let url = ''
for (const key in data)
{
const value = data[key]
const t = `${key}` + '=' + value
url += '&' + t
}
window.open(
` ${window._baseUrl}/reid/export`
+
`?token=${Cookies.get('token') + url}`
)
}
const getProjectMapByCompanyId = async function(companyId) {
const {data} = await projectApi.getProjectList(companyId)
let map = {}
for (const project of data)
{
map[project.name] = project.id
}
return map
}
const getImagePackageMapByProjectId = async function(projectId) {
const {data} = await imagePackageApi.getImagePackageList(
{
projectId: projectId
}
)
let map = {}
for (const imagePackage of data)
{
map[imagePackage.name] = imagePackage.id
}
return map
}
const onSelectCompanyInQuery = async function(companyId) {
exportDataForm.projectId = ''
exportDataForm.imagePackageId = ''
const map = await getProjectMapByCompanyId(parseInt(companyId))
cloneObject(projectMapInQuery, map)
}
const onSelectProjectInQuery = async function(projectId) {
exportDataForm.imagePackageId = ''
const map = await getImagePackageMapByProjectId(parseInt(projectId))
cloneObject(imagePackageMapInQuery, map)
}
const initialize = function() {
getCompanyMap(companyMap)
}
initialize()
return {
// scalar
isLoading,
// sequence
imagePackageList,
// mapping
exportDataForm,
companyMap,
projectMapInQuery,
imagePackageMapInQuery,
// function
onSelectCompanyInQuery,
onSelectProjectInQuery,
exportData,
}
},
}
)
</script>
<style lang="less" scoped>
@import "./LabelWorkbook.less";
</style>
.Labeling {
background: white;
}
.el-main {
margin: 0;
padding: 0;
}
.el-header {
padding: 0;
}
.isFolderSelected {
background: aquamarine;
}
.isSelected {
border: 2px solid #4487f7 !important;
}
.isSelected:after {
bottom: 0px;
right: 0px;
content: "";
position: absolute;
width: 0;
height: 0;
border-bottom: 42px solid #4487f7;
border-left: 42px solid transparent;
}
.isSelected:before {
content: '';
position: absolute;
width: 14px;
height: 8px;
background: transparent;
bottom: 12px;
right: 5px;
border: 2px solid white;
border-top: none;
border-right: none;
-webkit-transform: rotate(-55deg);
-ms-transform: rotate(-55deg);
transform: rotate(-55deg);
z-index: 9;
}
.single-image-parent {
position: relative;
border: 2px solid white;
text-align: center;
}
.single-image {
height: 300px;
width: 100%;
cursor: pointer;
}
.right-image-folder-list {
//border-radius: 10px;
margin: 10px 0;
}
<template>
<el-container class="Labeling">
<el-header height="auto">
<div style="display: flex;justify-content: space-between">
标注中
<a-button @click="goBack" style="margin: 0 0 10px 0">返回上一页</a-button>
</div>
</el-header>
<el-main>
<el-container>
<el-aside :width="'50%'">
<el-container>
<el-header height="auto">
<el-row>
<el-col :span="18">
文件夹数量:
<el-input v-model.trim="folderNum" @input="onFolderNumChange" placeholder="文件夹数量" size="small" style="width: 100px"></el-input>
分钟数:
<el-input v-model.trim="minuteNum" @input="onMinuteNumChange" placeholder="分钟数" size="small" style="width: 100px"></el-input>
<a-button @click="confirmSearch" :loading="isSearchLoading" type="primary">搜索选中数据</a-button>
</el-col>
<el-col :span="6">
<div style="display: flex;justify-content: flex-end">
<a-button @click="confirmMerge" :loading="isMergeLoading" type="primary" style="margin: 0 0 0 5px">合并(Q)</a-button>
<a-button @click="highQualityExtract" type="primary" style="margin: 0 0 0 10px">优质提取</a-button>
<a-button @click="confirmDeleteImages" type="danger" style="margin: 0 10px">删除图片</a-button>
</div>
</el-col>
</el-row>
<div>图片</div>
<div v-bind:class="{ 'isFolderSelected' : isLeftImageFolderChecked }"
style="display:flex;justify-content: flex-end"
>
<a-checkbox v-model:checked="isLeftImageFolderChecked"
@change="selectImageFolder(currentPersonUnid)"
style="margin: 5px 2px">
选择文件夹
</a-checkbox>
</div>
</el-header>
<el-main v-bind:class="{ 'isFolderSelected' : isLeftImageFolderChecked }">
<!-- <VirtualList-->
<!-- :dataList="leftPagedTableData"-->
<!-- @imageClick="selectImage"-->
<!-- :key="leftPagedTableData"-->
<!-- ></VirtualList>-->
<el-row v-for="row in leftPagedTableData">
<el-col :span="8" v-for="item in row" @click="selectImage(item.id)">
<div v-bind:class="{ 'isSelected': item.isSelected}"
class="single-image-parent flex-vertical-center"
@contextmenu.prevent=""
@click.right="previewImage(getImageUrl(item.picId))">
<el-image :src="getImageUrl(item.picId)"
:fit="'contain'"
class="single-image">
</el-image>
</div>
<div>
{{ item.createTime }} {{ getDirectionTitle(item.direction) }}
</div>
</el-col>
</el-row>
</el-main>
</el-container>
</el-aside>
<el-main>
<el-container>
<el-header>
<div style="display: flex;justify-content: space-between">
<span>
<a-button @click="lowQualityExtract" type="primary" style="margin: 0 10px">低质提取</a-button>
<a-button @click="recycle" type="primary">回收</a-button>
</span>
<a-button @click="completeLabel" type="primary">完成标注</a-button>
</div>
<div>文件夹</div>
</el-header>
<el-main>
<button id="right-anchor-button"></button>
<div v-for="(value, personUnid) in displayedRightPeopleImageMap"
class="right-image-folder-list"
:style="'border: 5px solid' + getFolderColor(value.list[0].status)"
v-bind:class="{ 'isFolderSelected' : value.isSelected }"
>
<div :style="'background: ' + getFolderColor(value.list[0].status)" style="height: 20px;color: white">{{ getFolderTitle(value.list[0].status) }}</div>
<a-checkbox @change="selectImageFolder(personUnid)" style="margin: 5px 2px">选择文件夹</a-checkbox>
<el-row v-for="row in getPagedList(value.list, 3)">
<el-col :span="8"
v-for="item in row"
@click="selectImage(item.id)"
style="content-visibility: auto"
>
<div v-bind:class="{ 'isSelected' : item.isSelected }"
@contextmenu.prevent=""
@click.right="previewImage(getImageUrl(item.picId))"
class="single-image-parent flex-vertical-center">
<el-image :src="getImageUrl(item.picId)"
:fit="'contain'"
class="single-image"
>
</el-image>
</div>
</el-col>
</el-row>
</div>
<a-button @click="isFilteredDataShowed = true" v-if="isFilterButtonShowed" type="primary" style="width: 100%">展开过滤数据</a-button>
<div v-if="isFilteredDataShowed">
<div v-for="(value, personUnid) in hiddenRightPeopleImageMap"
class="right-image-folder-list"
:style="'border: 5px solid' + getFolderColor(value.list[0].status)"
v-bind:class="{ 'isFolderSelected' : value.isSelected }"
>
<div :style="'background: ' + getFolderColor(value.list[0].status)" style="height: 20px;color: white">{{ getFolderTitle(value.list[0].status) }}</div>
<a-checkbox @change="selectImageFolder(personUnid)" style="margin: 5px 2px">选择文件夹</a-checkbox>
<el-row v-for="row in getPagedList(value.list, 3)">
<el-col :span="8"
v-for="item in row"
@click="selectImage(item.id)"
style="content-visibility: auto">
<div v-bind:class="{ 'isSelected' : item.isSelected }"
@contextmenu.prevent=""
@click.right="previewImage(getImageUrl(item.picId))"
class="single-image-parent flex-vertical-center">
<el-image :src="getImageUrl(item.picId)"
:fit="'contain'"
class="single-image">
</el-image>
</div>
</el-col>
</el-row>
</div>
</div>
</el-main>
</el-container>
</el-main>
</el-container>
</el-main>
<div style="display: flex;justify-content: flex-end">
<a-button @click="previousPerson">上一个</a-button>
<a-button @click="nextPerson">下一个</a-button>
</div>
</el-container>
</template>
<script>
import {useRoute} from 'vue-router'
import {
cloneObject,
emptyObject,
getPagedList,
getImageUrl,
resetForm,
filterEmptyValueInObject, getMinuteNum, getFolderNum, getFolderTitle, getFolderColor
} from '@/PublicUtil/PublicUtil'
import {computed, createVNode, onBeforeUnmount, reactive, ref} from 'vue'
import labelingApi from '@/views/DataLabel/Labeling/LabelingApi'
import {isEmptyArray, isNotEmptyArray} from '@/PublicUtil/Judgment'
import router from '@/router'
import {message, Modal} from 'ant-design-vue'
import {ExclamationCircleOutlined} from '@ant-design/icons-vue'
import VirtualList from '@/views/DataLabel/Labeling/VirtualList/VirtualList'
export default {
components: {
VirtualList,
},
setup() {
const packId = useRoute().query.packId
const currentPersonUnid = useRoute().query.personUnid
const status = useRoute().query.status
const isSearchLoading = ref(false)
const isMergeLoading = ref(false)
const isLeftImageFolderChecked = ref(true)
const ref_rightMain = ref()
const isFilterButtonShowed = ref(false)
const isFilteredDataShowed = ref(false)
const folderNum = ref(getFolderNum())
const minuteNum = ref(getMinuteNum())
const leftPeopleImageList = ref([])
const rightPeopleImageMap = reactive({})
const displayedRightPeopleImageMap = reactive({})
const hiddenRightPeopleImageMap = reactive({})
let selectedImageFolderIdList = [currentPersonUnid]
let allSelectedImageIdList = []
let leftSelectedImageIdList = []
let rightSelectedImageIdList = []
let webSocket = undefined
const leftPagedTableData = computed(
() => {
return getPagedList(leftPeopleImageList.value, 3)
}
)
const getPeopleImageList = function() {
labelingApi.getPeopleImageList(packId, currentPersonUnid).then(
(r) => {
leftPeopleImageList.value = r.data
for (const peopleImage of leftPeopleImageList.value)
{
peopleImage['isSelected'] = false
}
}
)
}
const resetAll = function() {
isMergeLoading.value = false
isFilterButtonShowed.value = false
isFilteredDataShowed.value = false
if (isLeftImageFolderChecked.value === true)
{
selectedImageFolderIdList = [currentPersonUnid]
}
else
{
selectedImageFolderIdList = []
}
leftSelectedImageIdList = []
rightSelectedImageIdList = []
allSelectedImageIdList = []
emptyObject(displayedRightPeopleImageMap)
emptyObject(hiddenRightPeopleImageMap)
emptyObject(rightPeopleImageMap)
getPeopleImageList()
}
const confirmMerge = function() {
log(selectedImageFolderIdList, allSelectedImageIdList)
isMergeLoading.value = true
if (
isEmptyArray(selectedImageFolderIdList)
&& isNotEmptyArray(allSelectedImageIdList)
)
{
// 没有文件夹被选中,有图片被选中
// 将多张图片合成新的文件夹
log(1, '没有文件夹被选中,有图片被选中')
labelingApi.mergeImagesAsNewPerson(
allSelectedImageIdList.toString(),
packId
).then(
(r) => {
message.info(r.msg)
resetAll()
}
)
}
else if (
isNotEmptyArray(selectedImageFolderIdList)
&& selectedImageFolderIdList.length !== 1
&& isEmptyArray(allSelectedImageIdList)
)
{
// 有多个文件夹被选中,没有图片被选中
// 将多个文件夹合成一个文件夹
log(2, '有多个文件夹被选中,没有图片被选中')
labelingApi.mergeMultiplePersonsAsNewPerson(
selectedImageFolderIdList.toString(),
packId,
currentPersonUnid
).then(
(r) => {
message.info(r.msg)
resetAll()
}
)
}
else if (
selectedImageFolderIdList.length === 1
&&
isNotEmptyArray(allSelectedImageIdList)
)
{
// 文件夹有一个被选中,有图片被选中
// 将多张图片合并到选中的一个文件夹中
log(3, '文件夹有一个被选中,有图片被选中')
labelingApi.mergeMultipleImagesToOnePerson(
allSelectedImageIdList.toString(),
selectedImageFolderIdList.toString(),
packId,
currentPersonUnid
).then(
(r) => {
message.info(r.msg)
resetAll()
}
)
}
else if (
isLeftImageFolderChecked.value === true
&&
selectedImageFolderIdList.length > 1
&&
isNotEmptyArray(rightSelectedImageIdList)
)
{
// 左侧文件夹被选中,右侧有文件夹和图片同时被选中
// 将多张图片合并到选中的一个文件夹中
log(4, '左侧文件夹被选中,右侧有文件夹和图片同时被选中')
labelingApi.mergeMultipleImagesToOnePerson(
allSelectedImageIdList.toString(),
currentPersonUnid,
packId,
currentPersonUnid
).then(
() => {
labelingApi.mergeMultiplePersonsAsNewPerson(
selectedImageFolderIdList.toString(),
packId,
currentPersonUnid
).then(
(r) => {
message.info(r.msg)
resetAll()
}
)
}
)
}
else
{
log(5)
message.info('选择格式错误')
isMergeLoading.value = false
}
}
const confirmSearch = function() {
document.getElementById("right-anchor-button").focus()
isSearchLoading.value = true
labelingApi.getSimilarPeopleImageFolderList(
leftSelectedImageIdList.toString(),
folderNum.value,
packId,
minuteNum.value,
currentPersonUnid,
).then(
(r) => {
isFilterButtonShowed.value = true
isSearchLoading.value = false
cloneObject(displayedRightPeopleImageMap, r.data.display)
cloneObject(hiddenRightPeopleImageMap, r.data.hide)
// 更改数据
for (let key in displayedRightPeopleImageMap)
{
const list = displayedRightPeopleImageMap[key]
for (let item of list)
{
item.isSelected = false
}
const value = {
isSelected: false,
list: list
}
displayedRightPeopleImageMap[key] = value
}
for (let key in hiddenRightPeopleImageMap)
{
const list = hiddenRightPeopleImageMap[key]
for (let item of list)
{
item.isSelected = false
}
const value = {
isSelected: false,
list: list
}
hiddenRightPeopleImageMap[key] = value
}
// 合并数据
for (let key in displayedRightPeopleImageMap)
{
const value = displayedRightPeopleImageMap[key]
rightPeopleImageMap[key] = value
}
for (let key in hiddenRightPeopleImageMap)
{
const value = hiddenRightPeopleImageMap[key]
rightPeopleImageMap[key] = value
}
// 置空数据
if (isLeftImageFolderChecked.value === true)
{
selectedImageFolderIdList = [currentPersonUnid]
}
else
{
selectedImageFolderIdList = []
}
leftSelectedImageIdList = []
rightSelectedImageIdList = []
allSelectedImageIdList = []
for (const peopleImage of leftPeopleImageList.value)
{
peopleImage['isSelected'] = false
}
}
)
}
const changeSelectedImageIdList = function(item, position) {
item['isSelected'] = !item['isSelected']
if (item['isSelected'] === true)
{
if (position === 'left')
{
leftSelectedImageIdList.push(item.id)
}
else
{
rightSelectedImageIdList.push(item.id)
}
}
else
{
if (position === 'left')
{
leftSelectedImageIdList.splice(leftSelectedImageIdList.indexOf(item.id), 1)
}
else
{
rightSelectedImageIdList.splice(rightSelectedImageIdList.indexOf(item.id), 1)
}
}
allSelectedImageIdList = leftSelectedImageIdList.concat(rightSelectedImageIdList)
}
const selectImage = function(id) {
for (let row of leftPagedTableData.value)
{
for (let item of row)
{
if (item.id === id)
{
changeSelectedImageIdList(item, 'left')
}
}
}
for (let key in rightPeopleImageMap)
{
const list = rightPeopleImageMap[key].list
for (let item of list)
{
if (item.id === id)
{
changeSelectedImageIdList(item, 'right')
}
}
}
}
const getValueOfRightPeopleImageMap = function(personUnid) {
for (const pUnid in rightPeopleImageMap)
{
const value = rightPeopleImageMap[pUnid]
if (pUnid === personUnid)
{
return value
}
}
}
const selectImageFolder = function(personUnid) {
if (selectedImageFolderIdList.includes(personUnid))
{
selectedImageFolderIdList.splice(selectedImageFolderIdList.indexOf(personUnid), 1)
if (personUnid !== currentPersonUnid)
{
getValueOfRightPeopleImageMap(personUnid).isSelected = false
}
}
else
{
selectedImageFolderIdList.push(personUnid)
if (personUnid !== currentPersonUnid)
{
getValueOfRightPeopleImageMap(personUnid).isSelected = true
}
}
}
const completeLabel = function() {
labelingApi.completeLabel(currentPersonUnid, packId).then(
(r) => {
message.info(r.msg)
}
)
webSocket.send('success')
nextPerson()
}
const confirmDeleteImages = function() {
Modal.confirm({
title: '确认要删除这些图片?',
icon: createVNode(ExclamationCircleOutlined),
okText: '是',
okType: 'danger',
cancelText: '否',
onOk() {
labelingApi.deleteImages(allSelectedImageIdList.toString(), packId).then(
(r) => {
message.info(r.msg)
resetAll()
}
)
},
})
}
const goBack = function() {
router.push(
{
path: '/DataLabel/PeopleLabel',
query: filterEmptyValueInObject(
{
packId: packId,
pageNum: localStorage.getItem('pageNum'),
}
)
}
)
}
onBeforeUnmount(
() => {
labelingApi.exitLabeling(currentPersonUnid, packId)
webSocket.close()
}
)
const previousPerson = function() {
const data = {
personUnid: currentPersonUnid,
packId: packId,
status: status,
}
labelingApi.getPreviousPerson(data).then(
(r) => {
if (r.msg === '没有数据了')
{
message.info('没有数据了')
}
else
{
router.push(
{
path: '/DataLabel/Labeling',
query: {
packId: packId,
personUnid: Object.keys(r.data)[0],
status: status,
}
}
)
}
}
)
}
const nextPerson = function() {
const data = {
personUnid: currentPersonUnid,
packId: packId,
status: status,
}
labelingApi.getNextPerson(data).then(
(r) => {
if (r.msg === '没有数据了')
{
message.info('没有数据了')
}
else
{
router.push(
{
path: '/DataLabel/Labeling',
query: {
packId: packId,
personUnid: Object.keys(r.data)[0],
status: status,
}
}
)
}
}
)
}
const recycle = function() {
if (selectedImageFolderIdList.length === 0 && allSelectedImageIdList.length !== 0)
{
labelingApi.recycle(selectedImageFolderIdList[0], allSelectedImageIdList.toString(), packId).then(
(r) => {
message.info(r.msg)
resetAll()
}
)
}
else if (selectedImageFolderIdList.length === 1)
{
labelingApi.recycle(selectedImageFolderIdList[0], allSelectedImageIdList.toString(), packId).then(
(r) => {
message.info(r.msg)
resetAll()
}
)
}
else
{
message.info('选择格式错误')
}
}
const onFolderNumChange = function(v) {
localStorage.setItem('folderNum', v)
}
const onMinuteNumChange = function(v) {
localStorage.setItem('minuteNum', v)
}
const highQualityExtract = function() {
if (selectedImageFolderIdList.length === 0 && allSelectedImageIdList.length === 0)
{
message.info('选择格式错误')
}
else
{
labelingApi.highQualityExtract(selectedImageFolderIdList.toString(), allSelectedImageIdList.toString(), packId, currentPersonUnid).then(
(r) => {
message.info(r.msg)
resetAll()
}
)
}
}
const lowQualityExtract = function() {
if (selectedImageFolderIdList.length === 0 && allSelectedImageIdList.length === 0)
{
message.info('选择格式错误')
}
else
{
const data = {
personUnidArr: selectedImageFolderIdList.toString(),
subTaskIdArr: allSelectedImageIdList.toString(),
packId: packId,
currentPerson: currentPersonUnid,
}
labelingApi.lowQualityExtract(data).then(
(r) => {
message.info(r.msg)
resetAll()
}
)
}
}
const initializeWebSocket = function() {
webSocket = new WebSocket(`ws://${window._serverHost}/reid/websocket/${packId}/${currentPersonUnid}`)
// webSocket.onmessage = function(event) {
// const rawData = event.data
// log(rawData)
// }
}
const previewImage = function(imageUrl) {
window.open(imageUrl)
}
const addShortcutKey = function(event) {
if (event.code === 'KeyQ')
{
confirmMerge()
}
}
const getDirectionTitle = function(v) {
switch (v)
{
case 1:
{
return '进'
}
case -1:
{
return '出'
}
default:
{
break
}
}
}
onBeforeUnmount(
() => {
document.removeEventListener('keydown', addShortcutKey)
}
)
const initialize = function() {
initializeWebSocket()
getPeopleImageList()
document.addEventListener('keydown', addShortcutKey)
}
initialize()
return {
// scalar
folderNum,
minuteNum,
isSearchLoading,
isMergeLoading,
ref_rightMain,
isLeftImageFolderChecked,
currentPersonUnid,
isFilterButtonShowed,
isFilteredDataShowed,
// sequence
leftPagedTableData,
// mapping
rightPeopleImageMap,
displayedRightPeopleImageMap,
hiddenRightPeopleImageMap,
// function
goBack,
confirmMerge,
confirmSearch,
selectImage,
getPagedList,
getImageUrl,
selectImageFolder,
completeLabel,
confirmDeleteImages,
previousPerson,
nextPerson,
previewImage,
recycle,
highQualityExtract,
lowQualityExtract,
onFolderNumChange,
onMinuteNumChange,
getFolderColor,
getFolderTitle,
getDirectionTitle,
}
}
}
</script>
<style lang="less" scoped>
@import "./Labeling.less";
</style>
import {axiosInstance} from "@/Request/PublicAxiosInstance"
import {filterEmptyValueInObject, getCountGte, getCountLte} from "@/PublicUtil/PublicUtil"
class LabelingApi {
getPeopleImageList(packId, personUnid) {
return axiosInstance.request(
{
method: 'GET',
url: `/subTasks`,
params: {
packId: packId,
personUnid: personUnid,
sortName: 'create_time'
},
}
)
}
getSimilarPeopleImageFolderList(picIdArr, folderNum, packId, minutes, currentPersonUnid) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/getSimilarPerson`,
params: {
picIdArr: picIdArr,
size: folderNum,
packId: packId,
timeInterval: minutes,
currentPerson: currentPersonUnid,
},
}
)
}
completeLabel(personUnid, packId) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/setPure`,
params: {
personUnid: personUnid,
packId: packId,
},
}
)
}
mergeImagesAsNewPerson(picIdArr, packId) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/mergeAsNewPerson`,
params: {
picIdArr: picIdArr,
packId: packId,
},
}
)
}
mergeMultiplePersonsAsNewPerson(personUnidArr, packId, currentPersonUnid) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/mergePerson`,
params: {
personUnidArr: personUnidArr,
packId: packId,
currentPerson: currentPersonUnid,
},
}
)
}
mergeMultipleImagesToOnePerson(picIdArr, personUnid, packId, currentPersonUnid) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/mergeTo`,
params: {
picIdArr: picIdArr,
personUnid: personUnid,
packId: packId,
currentPerson: currentPersonUnid,
},
}
)
}
deleteImages(picIdArr, packId) {
return axiosInstance.request(
{
method: 'DELETE',
url: `/reid/deletePic`,
params: {
picIdArr: picIdArr,
packId: packId,
},
}
)
}
recycle(personUnid, subTaskIdArr, packId) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/recovery`,
params: filterEmptyValueInObject(
{
personUnid: personUnid,
subTaskIdArr: subTaskIdArr,
packId: packId,
}
),
}
)
}
highQualityExtract(personUnid, subTaskIdArr, packId, currentPersonUnid) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/mergeAndTodo`,
params: filterEmptyValueInObject(
{
personUnidArr: personUnid,
subTaskIdArr: subTaskIdArr,
packId: packId,
currentPerson: currentPersonUnid,
}
),
}
)
}
lowQualityExtract(data) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/mergeAndLowQuality`,
params: filterEmptyValueInObject(
{
personUnidArr: data.personUnidArr,
subTaskIdArr: data.subTaskIdArr,
packId: data.packId,
currentPerson: data.currentPerson,
}
),
}
)
}
exitLabeling(personUnid, packId) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/exitLabeling`,
params: {
personUnid: personUnid,
packId: packId,
},
}
)
}
getPreviousPerson(data) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/getOtherPeople`,
params: filterEmptyValueInObject(
{
personUnid: data.personUnid,
packId: data.packId,
type: 1,
status: data.status,
countGTE: getCountGte(),
countLTE: getCountLte(),
}
),
}
)
}
getNextPerson(data) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/getOtherPeople`,
params: filterEmptyValueInObject(
{
personUnid: data.personUnid,
packId: data.packId,
type: 0,
status: data.status,
countGTE: getCountGte(),
countLTE: getCountLte(),
}
),
}
)
}
}
const labelingApi = new LabelingApi()
export default labelingApi
.container {
margin: 0;
padding: 0;
overflow: auto;
}
.clearfix::after {
content: '';
display: block;
clear: both;
}
.empty {
float: left;
}
.single-image-parent {
position: relative;
border: 2px solid white;
text-align: center;
}
.single-image {
height: 300px;
width: 100%;
cursor: pointer;
}
.el-row {
height: 326px !important;
}
.isSelected {
border: 2px solid #4487f7 !important;
}
.isSelected:after {
bottom: 0px;
right: 0px;
content: "";
position: absolute;
width: 0;
height: 0;
border-bottom: 42px solid #4487f7;
border-left: 42px solid transparent;
}
.isSelected:before {
content: '';
position: absolute;
width: 14px;
height: 8px;
background: transparent;
bottom: 12px;
right: 5px;
border: 2px solid white;
border-top: none;
border-right: none;
-webkit-transform: rotate(-55deg);
-ms-transform: rotate(-55deg);
transform: rotate(-55deg);
z-index: 9;
}
<template>
<div class="container clearfix" ref="containerRef" style="height: 100%">
<div class="empty" :style="{ height: emptyHeight }"></div>
<div :style="{ transform: `translateY(${translateY})` }">
<el-row v-for="row in showedList">
<el-col :span="8" v-for="item in row" @click="selectImage(item.id)">
<div v-bind:class="{ 'isSelected': item.isSelected}"
class="single-image-parent flex-vertical-center"
@contextmenu.prevent=""
@click.right="previewImage(getImageUrl(item.picId))">
<el-image :src="getImageUrl(item.picId)"
:fit="'contain'"
class="single-image">
</el-image>
</div>
<div>
{{ item.createTime }} {{ getDirectionTitle(item.direction) }}
</div>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import {computed, onMounted, ref} from 'vue'
import {getImageUrl, getPagedList, previewImage} from '@/PublicUtil/PublicUtil'
export default {
props: {
dataList: {
default: []
},
},
setup(props, {emit}) {
const dataList = props.dataList
const containerRef = ref()
const itemHeight = 326
const start = ref(0)
const translateY = ref(0)
const showedList = computed(
() => {
return dataList.slice(start.value, start.value + 3)
}
)
const emptyHeight = itemHeight * (dataList.length + 1)
const getDirectionTitle = function(v) {
switch (v)
{
case 1:
{
return '进'
}
case -1:
{
return '出'
}
default:
{
break
}
}
}
const selectImage = function(id) {
emit('imageClick', id)
}
onMounted(
() => {
containerRef.value.addEventListener(
'scroll',
(event) => {
const {scrollTop} = event.target
start.value = Math.floor(scrollTop / itemHeight)
translateY.value = scrollTop + 'px'
}
)
}
)
return {
containerRef,
translateY,
itemHeight: itemHeight + 'px',
emptyHeight: emptyHeight + 'px',
// sequence
showedList,
// function
selectImage,
getDirectionTitle,
getImageUrl,
previewImage,
}
}
}
</script>
<style lang="less" scoped>
@import "./VirtualList";
</style>
.PeopleLabel {
background: white;
}
.folder {
width: 400px;
cursor: pointer;
}
.folder-title {
color: white;
padding: 0 0 0 20px;
}
.folder-body {
//padding: 0 0 0 20px;
margin: 0 auto;
}
.folder-cover-image {
//width: 200px;
text-align: center
//padding: 0 0 0 20px;
}
.column-title-font {
padding: 0 0 0 18px
}
<template>
<a-layout class="PeopleLabel">
<div style="display: flex;justify-content: space-between">
标注
<a-button @click="goBack">返回上一页</a-button>
</div>
<div>
图片数量:
<el-input v-model.trim="countGTE" @input="onCountGteChange" size="mini" style="width: 150px"></el-input>
<el-input v-model.trim="countLTE" @input="onCountLteChange" size="mini" style="width: 150px"></el-input>
<a-button @click="getPeopleImageFolderList" type="primary">搜索</a-button>
</div>
<div>
文件夹ID:
<el-input v-model.trim="searchedFolderId" size="mini" style="width: 300px"></el-input>
<a-button @click="searchFolder" type="primary">搜索</a-button>
</div>
<el-row>
<el-col :span="18">
<el-menu mode="horizontal" @select="onMenuSelect" :default-active="'1'">
<el-menu-item :index="'1'">
待标注
</el-menu-item>
<el-menu-item :index="'2'">
标注中
</el-menu-item>
<el-menu-item :index="'3'">
完成标注
</el-menu-item>
<el-menu-item :index="'-1'">
被回收
</el-menu-item>
<el-menu-item :index="'4'">
优质
</el-menu-item>
<el-menu-item :index="'7'">
低质
</el-menu-item>
<el-menu-item :index="''">
全部
</el-menu-item>
<el-menu-item :index="'我的完成标注'">
我的完成标注
</el-menu-item>
</el-menu>
</el-col>
<el-col :span="6" v-if="isReviewAccessed">
<el-button @click="confirmSubmitReview(6)" type="success" size="small">审核通过</el-button>
<el-button @click="confirmSubmitReview(5)" type="danger" size="small">审核驳回</el-button>
</el-col>
</el-row>
<div style="height: 100%; overflow: scroll" v-loading="isLoading">
<el-row v-for="row in pagedTableData">
<el-col :span="6" v-for="item in row">
<el-checkbox @change="selectImageFolder(Object.keys(item)[0])" v-if="isReviewAccessed" :key="Object.keys(item)[0]">选择文件夹</el-checkbox>
<div @click="enterLabeling(Object.keys(item)[0])"
class="folder"
:style="'border: 1px solid ' + getFolderColor(Object.values(item)[0][0].status)"
>
<div class="folder-title"
:style="'background: ' + getFolderColor(Object.values(item)[0][0].status)"
>
{{ getFolderTitle(Object.values(item)[0][0].status) }}
</div>
<div class="folder-body ">
<div class="folder-cover-image">
<el-image :src="getImageUrl(Object.values(item)[0][0].picId)"
:fit="'contain'"
style="height: 300px;">
</el-image>
</div>
<el-row>
<el-col :span="6" class="column-title-font">文件夹ID:</el-col>
<el-col :span="18">{{ Object.keys(item)[0] }}</el-col>
</el-row>
<el-row>
<el-col :span="6" class="column-title-font">标注人:</el-col>
<el-col :span="18">{{ Object.values(item)[0][0].labelUserName }}</el-col>
</el-row>
<el-row>
<el-col :span="6" class="column-title-font">图片数量:</el-col>
<el-col :span="18">{{ Object.values(item)[0].length }}</el-col>
</el-row>
<!-- <el-row>-->
<!-- <el-col :span="10" class="column-title-font">创建时间:</el-col>-->
<!-- <el-col :span="14">{{ item.createTime }}</el-col>-->
<!-- </el-row>-->
<!-- <el-row>-->
<!-- <el-col :span="10" class="column-title-font">完成时间:</el-col>-->
<!-- <el-col :span="14">2020-2-3 23:23:43</el-col>-->
<!-- </el-row>-->
</div>
</div>
</el-col>
</el-row>
<el-pagination @current-change="handlePageNumChange"
@size-change="handlePageSizeChange"
:current-page="pageNum"
:page-size="pageSize"
:total="total"
:page-sizes="[12, 24, 36, 48]"
layout="total, sizes, prev, pager, next, jumper"
style="text-align:center"
>
</el-pagination>
</div>
</a-layout>
</template>
<script>
import {computed, defineComponent, reactive, ref, toRefs, watch} from 'vue'
import {useRoute, useRouter} from 'vue-router'
import peopleLabelApi from '@/views/DataLabel/PeopleLabel/PeopleLabelApi'
import {
formatPaginatedTableData,
getCountGte,
getCountLte, getFolderColor,
getFolderTitle,
getImageUrl,
getPagedList,
} from '@/PublicUtil/PublicUtil'
import {message} from 'ant-design-vue'
import router from '@/router'
import {isEmptyValue, isNotEmptyValue} from '@/PublicUtil/Judgment'
import {ElMessage} from 'element-plus'
export default defineComponent(
{
setup() {
const getPageNum = function() {
const pageNum = useRoute().query.pageNum
if (isEmptyValue(pageNum))
{
return 1
}
else
{
return pageNum
}
}
const pageNum = ref(getPageNum())
const pageSize = ref(12)
const total = ref(Number.MAX_SAFE_INTEGER)
const isLoading = ref(false)
const packId = useRoute().query.packId
const isReviewAccessed = useRoute().query.isReviewAccessed === 'true'
const router = useRouter()
const imageData = ref()
const countGTE = ref(getCountGte())
const countLTE = ref(getCountLte())
const searchedFolderId = ref()
let selectedMenuIndex = '1'
const pagedTableData = computed(
() => {
return getPagedList(peopleFolderList.value, 4)
}
)
// sequence
const peopleFolderList = ref([])
let selectedImageFolderIdList = []
// function
const handlePageNumChange = function(num) {
pageNum.value = num
selectedImageFolderIdList = []
getPeopleImageFolderList()
if (isNotEmptyValue(pageNum.value))
{
localStorage.setItem('pageNum', pageNum.value)
}
}
const handlePageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
selectedImageFolderIdList = []
getPeopleImageFolderList()
if (isNotEmptyValue(pageNum.value))
{
localStorage.setItem('pageNum', pageNum.value)
}
}
const enterLabeling = function(personUnid) {
peopleLabelApi.enterLabeling(personUnid, packId).then(
(r) => {
if (r.msg === '正在被其他人标注')
{
message.info('正在被其他人标注')
}
else
{
router.push(
{
path: '/DataLabel/Labeling',
query: {
packId: packId,
personUnid: personUnid,
status: selectedMenuIndex,
}
}
)
}
}
)
}
const getPeopleImageFolderList = function() {
isLoading.value = true
const data = {
packId: packId,
status: selectedMenuIndex === '我的完成标注' ? undefined : selectedMenuIndex,
annotatorId: selectedMenuIndex === '我的完成标注' ? localStorage.getItem('currentUserId') : undefined,
pageNum: pageNum.value,
pageSize: pageSize.value,
countGTE: getCountGte(),
countLTE: getCountLte(),
}
peopleLabelApi.getPeopleImageFolderList(data).then(
({data}) => {
formatPaginatedTableData(
peopleFolderList,
data,
total,
)
isLoading.value = false
}
)
}
const searchFolder = function() {
isLoading.value = true
const data = {
personUnid_like: searchedFolderId.value,
packId: packId,
}
peopleLabelApi.searchFolder(data).then(
({data}) => {
isLoading.value = false
let l = []
for (let key in data)
{
const value = data[key]
l.push(
{
[key]: value
}
)
}
peopleFolderList.value = l
// total.value = data.length
}
)
}
const goBack = function() {
router.push(
{
path: '/DataLabel/ImagePackage',
}
)
}
const getFolderTitleBorderColor = function(status) {
switch (status)
{
case 1:
{
return 'folder-title-toBeLabeled'
}
case 2:
{
return 'folder-title-labeling'
}
case 3:
{
return 'folder-title-labeled'
}
case -1:
{
return 'folder-title-beRecycled'
}
case 4:
{
return 'folder-title-highQuality'
}
default:
{
return ''
}
}
}
const onMenuSelect = function(index) {
selectedMenuIndex = index
getPeopleImageFolderList()
}
const onCountGteChange = function(v) {
localStorage.setItem('countGTE', v)
}
const onCountLteChange = function(v) {
localStorage.setItem('countLTE', v)
}
const selectImageFolder = function(personUnid) {
if (selectedImageFolderIdList.includes(personUnid))
{
selectedImageFolderIdList.splice(selectedImageFolderIdList.indexOf(personUnid), 1)
}
else
{
selectedImageFolderIdList.push(personUnid)
}
}
const confirmSubmitReview = function(status) {
const data = {
personUnidArr: selectedImageFolderIdList,
status: status,
}
peopleLabelApi.submitReview(data).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
}
)
}
const initialize = function() {
getPeopleImageFolderList()
}
initialize()
return {
// scalar
pageNum,
pageSize,
total,
isLoading,
imageData,
countGTE,
countLTE,
searchedFolderId,
isReviewAccessed,
// sequence
peopleFolderList,
pagedTableData,
// mapping
// function
handlePageNumChange,
handlePageSizeChange,
getPeopleImageFolderList,
goBack,
getFolderTitle,
getFolderColor,
getFolderTitleBorderColor,
enterLabeling,
onMenuSelect,
getImageUrl,
onCountGteChange,
onCountLteChange,
searchFolder,
selectImageFolder,
confirmSubmitReview,
}
},
}
)
</script>
<style lang="less" scoped>
@import "./PeopleLabel.less";
</style>
import {axiosInstance} from "@/Request/PublicAxiosInstance"
import {filterEmptyValueInObject} from "@/PublicUtil/PublicUtil"
class PeopleLabelApi {
getPeopleImageFolderList(data) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/getPeople`,
params: filterEmptyValueInObject(
{
packId: data.packId,
status: data.status,
annotatorId: data.annotatorId,
page: data.pageNum,
size: data.pageSize,
countGTE: data.countGTE,
countLTE: data.countLTE,
}
),
}
)
}
enterLabeling(personUnid, packId) {
return axiosInstance.request(
{
method: 'GET',
url: `/reid/labeling`,
params: filterEmptyValueInObject(
{
personUnid: personUnid,
packId: packId,
}
),
}
)
}
searchFolder(data) {
return axiosInstance.request(
{
method: 'GET',
url: `/subTasks`,
params: filterEmptyValueInObject(
{
personUnid_like: '%' + data.personUnid_like + '%',
packId: data.packId,
group: 'true',
sortName: 'create_time'
}
),
}
)
}
submitReview(data) {
return axiosInstance.request(
{
method: 'POST',
url: `/reid/verify`,
data: filterEmptyValueInObject(
{
personUnidArr: data.personUnidArr,
status: data.status,
}
),
}
)
}
}
const peopleLabelApi = new PeopleLabelApi()
export default peopleLabelApi
.ProjectManagement {
.el-header {
display: flex;
margin: 0 20px;
align-items: center;
background: #FFFFFF;
}
.el-main {
margin: 20px;
padding: 20px;
background: #FFFFFF;
.project-form {
padding: 40px 40px 0 20px
}
}
}
<template>
<el-container class="QualityInspectManagement">
<el-header height="50px">
<div>
<span class="title-text">提交质检</span>
</div>
</el-header>
<el-main>
<el-menu mode="horizontal" @select="handleMenuSelect" :default-active="'1'">
<el-menu-item :index="'1'">
待标注
</el-menu-item>
<el-menu-item :index="'5'">
审核驳回
</el-menu-item>
<el-menu-item :index="'6'">
审核通过
</el-menu-item>
</el-menu>
<el-table :data="qualityInspectList" v-loading="isLoading">
<el-table-column prop="taskName" label="taskName" align="center"></el-table-column>
<el-table-column prop="packName" label="packName" align="center"></el-table-column>
<el-table-column prop="accountId" label="所属公司" align="center">
<template #default="scope">
{{ companyMap[scope.row.accountId] }}
</template>
</el-table-column>
<el-table-column prop="count" label="count" align="center"></el-table-column>
<el-table-column prop="finishCount" label="finishCount" align="center"></el-table-column>
<el-table-column prop="toBeLabeledCount" label="toBeLabeledCount" align="center"></el-table-column>
<el-table-column prop="operation" label="操作" align="center">
<template #default="scope">
<el-button @click="submitInspect(scope.row.packId)" type="text">提交审核</el-button>
<el-button @click="viewDetails(scope.row.packId)" type="text">查看详情</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</template>
<script>
import {reactive, ref, toRaw,} from "vue"
import {
filterEmptyValueInObject, getKeyByValueInObject,
resetForm
} from "@/PublicUtil/PublicUtil"
import qualityInspectApi from './SubmitQualityInspectApi'
import {ElMessageBox} from 'element-plus'
import {ElMessage} from 'element-plus'
import {getCompanyMap} from '@/Request/DictionaryRequest'
import {useRouter} from 'vue-router'
export default {
setup() {
// scalar
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref()
const isLoading = ref(false)
const router = useRouter()
let selectedMenuIndex = '1'
const qualityInspectList = ref([])
// computed
// mapping
const companyMap = reactive({})
// function
const handlePageNumChange = function(num) {
pageNum.value = num
getQualityInspectList()
}
const handlePageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
getQualityInspectList()
}
const handleMenuSelect = function(index) {
selectedMenuIndex = index
getQualityInspectList()
}
const viewDetails = function(packId) {
router.push(
{
path: '/DataLabel/PeopleLabel',
query: {
packId: packId,
pageNum: 1,
}
}
)
}
const submitInspect = function(id) {
qualityInspectApi.submitInspect(id).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
}
)
}
const getQualityInspectList = function() {
isLoading.value = true
qualityInspectApi.getQualityInspectList(selectedMenuIndex).then(
({data}) => {
isLoading.value = false
qualityInspectList.value = data
// formatPaginatedTableData(
// qualityInspectList,
// data,
// total,
// )
}
)
}
const initialize = function() {
getQualityInspectList()
getCompanyMap(companyMap)
}
initialize()
return {
// scalar
pageNum,
pageSize,
total,
isLoading,
qualityInspectList,
// mapping
companyMap,
// function
handlePageNumChange,
handlePageSizeChange,
getKeyByValueInObject,
handleMenuSelect,
viewDetails,
submitInspect,
}
},
}
</script>
<style lang="less" scoped>
@import "./SubmitQualityInspect.less";
</style>
import {axiosInstance} from '@/Request/PublicAxiosInstance'
import {filterEmptyValueInObject,} from "@/PublicUtil/PublicUtil"
class QualityInspectApi {
getQualityInspectList(status) {
return axiosInstance.request(
{
method: 'GET',
url: '/packs/info',
params: filterEmptyValueInObject(
{
accountId: localStorage.getItem('currentAccountId'),
status: status,
}
)
}
)
}
submitInspect(id) {
return axiosInstance.request(
{
method: 'POST',
url: `/packs/${id}`,
data: {
status: 1
}
}
)
}
}
const qualityInspectApi = new QualityInspectApi()
export default qualityInspectApi
import {axiosInstance2} from "@/Request/PublicAxiosInstance"
import {filterEmptyValueInObject, getFormDataByObject, } from "@/PublicUtil/PublicUtil"
class JudgePeopleApi {
notSamePerson(id) {
return axiosInstance2.request(
{
method: 'POST',
url: `/clean2/${id}`,
data: getFormDataByObject(
{
same: 0
}
)
}
)
}
samePerson(id) {
return axiosInstance2.request(
{
method: 'POST',
url: `/clean2/${id}`,
data: getFormDataByObject(
{
same: 1
}
)
}
)
}
}
const judgePeopleApi = new JudgePeopleApi()
export default judgePeopleApi
.Labeling {
background: white;
}
.el-main {
margin: 0;
padding: 0;
}
.el-header {
padding: 0;
}
.isSelected {
border: 2px solid #4487f7 !important;
}
.isFolderSelected {
background: aquamarine;
}
.isSelected:after {
bottom: 0px;
right: 0px;
content: "";
position: absolute;
width: 0;
height: 0;
border-bottom: 42px solid #4487f7;
border-left: 42px solid transparent;
}
.isSelected:before {
content: '';
position: absolute;
width: 14px;
height: 8px;
background: transparent;
bottom: 12px;
right: 5px;
border: 2px solid white;
border-top: none;
border-right: none;
-webkit-transform: rotate(-55deg);
-ms-transform: rotate(-55deg);
transform: rotate(-55deg);
z-index: 9;
}
.single-image-parent {
//display: inline-block;
position: relative;
border: 2px solid white;
text-align: center;
}
.single-image {
height: 300px;
width: 100%;
}
.right-image-folder-list {
//border-radius: 10px;
margin: 10px 0;
}
<template>
<el-container>
<el-header style="height: 100px">
<div style="display:flex; justify-content: flex-end ">
<el-button @click="goBack">返回上一页</el-button>
</div>
<div style="font-size: 20px">
是否是一个人:{{ same }}
</div>
<el-row>
<el-col :span="12">
<span style="font-size: 20px">ID:{{ leftPersonUnid }}</span>
</el-col>
<el-col :span="12">
<span style="font-size: 20px">ID:{{ rightPersonUnid }}</span>
</el-col>
</el-row>
</el-header>
<el-main>
<el-container>
<el-aside :width="'50%'" style="border-right: red 1px solid">
<!-- <VirtualList-->
<!-- :dataList="leftPagedTableData"-->
<!-- :key="leftPagedTableData"-->
<!-- @imageClick="selectImage"-->
<!-- >-->
<!-- </VirtualList>-->
<el-row v-for="row in leftPagedTableData">
<el-col :span="8" v-for="item in row" @click="selectImage(item.id)">
<div v-bind:class="{ 'isSelected': item.isSelected}"
class="single-image-parent flex-vertical-center">
<el-image :src="getImageUrl(item.picId)"
:fit="'contain'"
class="single-image">
</el-image>
</div>
</el-col>
</el-row>
</el-aside>
<el-main>
<!-- <VirtualList-->
<!-- :dataList="rightPagedTableData"-->
<!-- :key="rightPagedTableData"-->
<!-- @imageClick="selectImage"-->
<!-- >-->
<!-- </VirtualList>-->
<el-row v-for="row in rightPagedTableData">
<el-col :span="8" v-for="item in row" @click="selectImage(item.id)">
<div v-bind:class="{ 'isSelected': item.isSelected}"
class="single-image-parent flex-vertical-center">
<el-image :src="getImageUrl(item.picId)"
:fit="'contain'"
class="single-image">
</el-image>
</div>
</el-col>
</el-row>
</el-main>
</el-container>
</el-main>
<el-footer>
<div style="display: flex; justify-content:flex-end;height: 100%" class="flex-vertical-center">
<el-button @click="splitImage">拆分图片(Q)</el-button>
<el-button type="danger" @click="notSamePerson">不是一个人(A)</el-button>
<el-button type="primary" @click="samePerson">是一个人(D)</el-button>
</div>
</el-footer>
</el-container>
</template>
<script>
import {useRoute, useRouter} from 'vue-router'
import {
getPagedList,
getImageUrl,
} from '@/PublicUtil/PublicUtil'
import {computed, onBeforeUnmount, reactive, ref} from 'vue'
import labelingApi from '@/views/DataLabel/Labeling/LabelingApi'
import judgePeopleApi from '@/views/JudgePeople/JudgePeople'
import {ElMessage} from 'element-plus'
import dataCleanApi from '@/views/ClassAmongClean/ClassAmongClean'
import VirtualList from '@/views/DataLabel/Labeling/VirtualList/VirtualList'
export default {
components: {
VirtualList,
},
setup() {
const id = useRoute().query.id
const packId = useRoute().query.packId
const name = useRoute().query.name
const packName = useRoute().query.packName
const same = useRoute().query.same
const leftPersonUnid = useRoute().query.leftPersonId
const rightPersonUnid = useRoute().query.rightPersonId
const personId = useRoute().query.personId
const leftPeopleImageList = ref([])
const rightPeopleImageList = ref([])
let leftSelectedImageIdList = []
let rightSelectedImageIdList = []
let allSelectedImageIdList = []
const router = useRouter()
const leftPagedTableData = computed(
() => {
return getPagedList(leftPeopleImageList.value, 3)
}
)
const rightPagedTableData = computed(
() => {
return getPagedList(rightPeopleImageList.value, 3)
}
)
const getLeftPeopleImageList = function() {
labelingApi.getPeopleImageList(packId, leftPersonUnid).then(
(r) => {
leftPeopleImageList.value = r.data
for (const peopleImage of leftPeopleImageList.value)
{
peopleImage['isSelected'] = false
}
}
)
}
const getRightPeopleImageList = function() {
labelingApi.getPeopleImageList(packId, rightPersonUnid).then(
(r) => {
rightPeopleImageList.value = r.data
for (const peopleImage of rightPeopleImageList.value)
{
peopleImage['isSelected'] = false
}
}
)
}
const nextJudge = function() {
const data = {
packId: packId
}
dataCleanApi.getCleanAmongResult(data).then(
(r) => {
const data = r.data
if (r.code === 200)
{
router.push(
{
path: '/JudgePeople',
query: {
id: data.id,
packId: packId,
leftPersonId: data.personId,
rightPersonId: data.simPersonId,
}
}
)
}
else
{
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
}
}
)
}
const notSamePerson = function() {
judgePeopleApi.notSamePerson(id).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
if (r.code === 200)
{
nextJudge()
}
}
)
}
const samePerson = function() {
judgePeopleApi.samePerson(id).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
if (r.code === 200)
{
nextJudge()
}
}
)
}
const goBack = function() {
router.push(
{
path: '/ClassAmongClean',
query: {
packId: packId,
name: name,
packName: packName,
}
}
)
}
const splitImage = function() {
labelingApi.mergeImagesAsNewPerson(
allSelectedImageIdList.toString(),
packId
).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
window.location.reload()
}
)
}
const changeSelectedImageIdList = function(item, position) {
item['isSelected'] = !item['isSelected']
if (item['isSelected'] === true)
{
if (position === 'left')
{
leftSelectedImageIdList.push(item.id)
}
else
{
rightSelectedImageIdList.push(item.id)
}
}
else
{
if (position === 'left')
{
leftSelectedImageIdList.splice(leftSelectedImageIdList.indexOf(item.id), 1)
}
else
{
rightSelectedImageIdList.splice(rightSelectedImageIdList.indexOf(item.id), 1)
}
}
allSelectedImageIdList = leftSelectedImageIdList.concat(rightSelectedImageIdList)
allSelectedImageIdList = [...new Set(allSelectedImageIdList)]
}
const selectImage = function(id) {
for (let row of leftPagedTableData.value)
{
for (let item of row)
{
if (item.id === id)
{
changeSelectedImageIdList(item, 'left')
}
}
}
for (let row of rightPagedTableData.value)
{
for (let item of row)
{
if (item.id === id)
{
changeSelectedImageIdList(item, 'right')
}
}
}
}
const addShortcutKey = function(event) {
if (event.code === 'KeyA')
{
notSamePerson()
}
if (event.code === 'KeyD')
{
samePerson()
}
if (event.code === 'KeyQ')
{
splitImage()
}
}
onBeforeUnmount(
() => {
document.removeEventListener('keydown', addShortcutKey)
}
)
const initialize = function() {
getLeftPeopleImageList()
getRightPeopleImageList()
document.addEventListener('keydown', addShortcutKey)
}
initialize()
return {
// scalar
same,
leftPersonUnid,
rightPersonUnid,
// sequence
leftPagedTableData,
rightPagedTableData,
// mapping
// function
notSamePerson,
samePerson,
getImageUrl,
goBack,
splitImage,
selectImage,
}
}
}
</script>
<style lang="less" scoped>
@import "./JudgePeople.less";
</style>
<template>
<a-form :model="loginForm">
<a-form-item label="用户名">
<a-input v-model:value="loginForm.username"/>
</a-form-item>
<a-form-item label="密码">
<a-input v-model:value="loginForm.password"/>
</a-form-item>
<a-form-item>
<a-button type="primary" @click="onSubmit">登录</a-button>
</a-form-item>
</a-form>
</template>
<script>
import {defineComponent, reactive, toRaw} from 'vue'
import {getAccessedMenu, setAccessedMenu} from '@/PublicUtil/PublicUtil'
import loginApi from '@/views/Login/LoginApi'
import Cookies from "js-cookie"
import {useRouter} from 'vue-router'
import {getUrlByTitle} from '@/router'
import {ElMessage} from 'element-plus'
export default defineComponent({
setup() {
const router = useRouter()
const loginForm = reactive(
{
username: window.location.hostname === "localhost" ? 'vion' : '',
password: window.location.hostname === "localhost" ? 'VION20050620' : '',
}
)
const onSubmit = () => {
const data = {
username: loginForm.username,
password: loginForm.password
}
loginApi.login(data).then(
(r) => {
const message = r.msg
if (message === 'success')
{
const data = r.data
const token = data.tokenInfo.tokenValue
Cookies.set("token", token)
// store.commit("setAccessedRouteList", getAccessedRouteList(r.data.menu))
setAccessedMenu(data.menu)
localStorage.setItem('currentUserId', data.id)
localStorage.setItem('currentUserType', data.type)
localStorage.setItem('currentAccountId', data.accountId)
const accessedMenu = getAccessedMenu()
const firstTitle = accessedMenu[Object.keys(accessedMenu)[0]][0]
router.push(
getUrlByTitle(firstTitle)
)
}
else
{
ElMessage(
{
message: `${message}`,
type: 'error'
}
)
}
}
)
}
return {
loginForm,
onSubmit,
}
},
})
</script>
<style scoped>
</style>
import {axiosInstance} from "@/Request/PublicAxiosInstance"
import {filterEmptyValueInObject} from "@/PublicUtil/PublicUtil"
class LoginApi {
login(data) {
return axiosInstance.request(
{
method: 'POST',
url: `/users/login`,
data: data,
}
)
}
logout() {
return axiosInstance.request(
{
method: 'GET',
url: `/users/logout`,
}
)
}
}
const loginApi = new LoginApi()
export default loginApi
File mode changed
<template>
<el-container>
<el-aside width="200px">
<div class="logo"/>
<el-menu :router="true" :default-openeds="getOpeneds()">
<el-submenu v-for="(list, name ,index) in accessedMenu" :index="index" :key="index">
<template #title>
<span>{{ name }}</span>
</template>
<el-menu-item-group>
<el-menu-item v-for="(title, i) in list" :index="getUrlByTitle(title)" :key="i">
{{
title
}}
</el-menu-item>
</el-menu-item-group>
</el-submenu>
<!-- <el-submenu :index="100">-->
<!-- <template #title>-->
<!-- <span> 数据清洗 </span>-->
<!-- </template>-->
<!-- <el-menu-item-group>-->
<!-- <el-menu-item :index="'/DataClean/DataClean'">-->
<!-- 数据清洗-->
<!-- </el-menu-item>-->
<!-- </el-menu-item-group>-->
<!-- </el-submenu>-->
</el-menu>
</el-aside>
<el-container>
<el-header style="background: #fff; padding: 0;height: 35px">
<div style="display: flex; justify-content: flex-end;">
<el-button @click="logout">退出登录</el-button>
</div>
</el-header>
<el-main>
<router-view :key="$route.fullPath"></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
import {defineComponent, ref} from 'vue'
import {useRouter} from 'vue-router'
import {getAccessedMenu,} from '@/PublicUtil/PublicUtil'
import {getUrlByTitle} from '@/router'
import loginApi from '@/views/Login/LoginApi'
export default defineComponent({
setup() {
const accessedMenu = getAccessedMenu()
const router = useRouter()
const goto = function(path) {
router.push(path)
}
const getOpeneds = function() {
let result = []
for (let i = 0; i < 1000; i++)
{
result.push(i)
}
return result
}
const logout = function() {
loginApi.logout().then(
() => {
router.push('/')
}
)
}
const initialize = function() {
// log(accessedMenu)
}
initialize()
return {
// scalar
// sequence
// mapping
accessedMenu,
// function
goto,
getUrlByTitle,
getOpeneds,
logout,
}
},
})
</script>
<style>
</style>
<template>
<el-container class="ProjectManagement">
<el-header height="50px">
<div>
<span class="title-text">项目管理</span>
</div>
</el-header>
<el-main>
<el-button type="primary" @click="addProject">新建</el-button>
<el-menu mode="horizontal" @select="handleMenuSelect" :default-active="'1'">
<el-menu-item :index="'1'">
待标注
</el-menu-item>
</el-menu>
<el-table :data="projectList" v-loading="isLoading">
<el-table-column prop="name" label="名称" align="center"></el-table-column>
<el-table-column prop="description" label="备注" align="center"></el-table-column>
<el-table-column prop="status" label="状态" align="center">
<template #default="scope">
{{ getStatusTitle(scope.row.status) }}
</template>
</el-table-column>
<el-table-column prop="accountId" label="所属公司" align="center">
<template #default="scope">
{{ companyMap[scope.row.accountId] }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
<el-table-column prop="operation" label="操作" align="center">
<template #default="scope">
<el-button @click="startProject(scope.row.id)" type="text">开启</el-button>
<el-button @click="finishProject(scope.row.id)" type="text">结束</el-button>
<el-button @click="distributeBatch(scope.row.id)" type="text">分配批次</el-button>
<el-button @click="editProject(scope.row)" type="text">编辑</el-button>
<el-button @click="distributeProject(scope.row)" type="text">分配公司</el-button>
</template>
</el-table-column>
</el-table>
<el-drawer title="新建项目" v-model="addProjectVisible" :destroy-on-close="true" :direction="'rtl'">
<div class="project-form">
<el-form :model="addProjectForm" :rules="rules" ref="ref_addProjectForm">
<el-form-item label="名称:" prop="name" :label-width="'120px'">
<el-input v-model.trim="addProjectForm.name"></el-input>
</el-form-item>
<el-form-item label="备注:" prop="description" :label-width="'120px'">
<el-input v-model.trim="addProjectForm.description" style="width: 100%"></el-input>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="addProjectVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmAddProject">确 定</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
<el-drawer title="编辑项目" v-model="editProjectVisible" :destroy-on-close="true" :direction="'rtl'">
<div class="project-form">
<el-form :model="editProjectForm" :rules="rules" ref="ref_editProjectForm">
<el-form-item label="名称:" prop="name" :label-width="'120px'">
<el-input v-model.trim="editProjectForm.name"></el-input>
</el-form-item>
<el-form-item label="备注:" prop="description" :label-width="'120px'">
<el-input v-model.trim="editProjectForm.description" style="width: 100%"></el-input>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="editProjectVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmEditProject">确 定</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
<el-drawer title="分配公司" v-model="distributeProjectVisible" :destroy-on-close="true" :direction="'rtl'">
<div class="project-form">
<el-form :model="distributeProjectForm">
<el-form-item label="公司:" :label-width="'120px'">
<el-select v-model="distributeProjectForm.accountId" style="width: 100%">
<el-option v-for="(name, value) in companyMap" :label="name" :value="parseInt(value)"></el-option>
</el-select>
</el-form-item>
<el-form-item style="text-align:center">
<el-button @click="distributeProjectVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmDistributeProject">确 定</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
<el-drawer title="分配批次" v-model="distributeBatchVisible" :size="'35%'" :destroy-on-close="true" :direction="'rtl'">
<div class="project-form">
<el-transfer v-model="usedBatchList"
:data="allBatchList"
:titles="['未分配', '已分配']"
@change="onBatchListChange"
/>
</div>
</el-drawer>
</el-main>
</el-container>
</template>
<script>
import {reactive, ref, toRaw,} from "vue"
import {
emptyList,
filterEmptyValueInObject, getKeyByValueInObject,
resetForm
} from "@/PublicUtil/PublicUtil"
import projectApi from './ProjectManagementApi'
import {ElMessageBox} from 'element-plus'
import {ElMessage} from 'element-plus'
import {getCompanyMap} from '@/Request/DictionaryRequest'
export default {
setup() {
// scalar
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref()
const isLoading = ref(false)
const addProjectVisible = ref(false)
const editProjectVisible = ref(false)
const distributeProjectVisible = ref(false)
const distributeBatchVisible = ref(false)
let selectedMenuIndex = '1'
const ref_addProjectForm = ref()
const ref_editProjectForm = ref()
let currentTaskId = undefined
// sequence
const projectList = ref([])
const usedBatchList = ref([])
const allBatchList = ref([])
// mapping
const rules = reactive(
{
// projectName: [
// {
// required: true,
// message: '请输入项目名称',
// },
// ],
// projectYear: [
// {
// type: 'date',
// required: true,
// message: '请输入建成年份',
// trigger: 'change'
// }
// ],
// groupId: [
// {
// required: true,
// message: '请选择集团',
// },
// ],
}
)
const companyMap = reactive({})
const addProjectForm = reactive(
{
name: '',
description: '',
}
)
const editProjectForm = reactive(
{
name: '',
description: '',
id: '',
}
)
const distributeProjectForm = reactive(
{
accountId: '',
id: '',
}
)
// function
const handlePageNumChange = function(num) {
pageNum.value = num
getProjectList()
}
const handlePageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
getProjectList()
}
const confirmAddProject = function() {
ref_addProjectForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(addProjectForm)
const data = filterEmptyValueInObject(rawData)
projectApi.addProject(data).then(
(r) => {
addProjectVisible.value = false
const message = r.msg
ElMessage(`${message}`)
getProjectList()
}
)
}
}
)
}
const confirmDistributeProject = function() {
const rawData = toRaw(distributeProjectForm)
const data = filterEmptyValueInObject(
{
accountId: rawData.accountId
}
)
projectApi.editProject(rawData.id, data).then(
(r) => {
distributeProjectVisible.value = false
const message = r.msg
ElMessage(`${message}`)
getProjectList()
}
)
}
const editProject = function(row) {
log(row)
editProjectVisible.value = true
editProjectForm.name = row.name
editProjectForm.description = row.description
editProjectForm.id = row.id
}
const confirmEditProject = function() {
ref_editProjectForm.value.validate(
(isValid) => {
if (isValid)
{
const rawData = toRaw(editProjectForm)
const data = filterEmptyValueInObject(
{
name: rawData.name,
description: rawData.description,
}
)
projectApi.editProject(rawData.id, data).then(
(r) => {
const message = r.msg
getProjectList()
ElMessage(`${message}`)
}
)
editProjectVisible.value = false
}
}
)
}
const distributeProject = function(row) {
distributeProjectVisible.value = true
distributeProjectForm.id = row.id
distributeProjectForm.accountId = row.accountId
}
const addProject = function() {
resetForm(addProjectForm)
addProjectVisible.value = true
}
const getProjectList = function() {
isLoading.value = true
projectApi.getProjectList().then(
({data}) => {
isLoading.value = false
projectList.value = data
// formatPaginatedTableData(
// projectList,
// data,
// total,
// )
}
)
}
const onBatchListChange = function(v, direction, changedList) {
const data = {
taskId: currentTaskId,
packIds: changedList.toString(),
}
if (direction === 'right') // add
{
projectApi.distributeBatch(data).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
}
)
}
else // delete
{
projectApi.cancelDistributeBatch(data).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
}
)
}
}
const distributeBatch = function(id) {
distributeBatchVisible.value = true
currentTaskId = id
emptyList(allBatchList.value)
emptyList(usedBatchList.value)
projectApi.getUsedBatchList(id).then(
({data}) => {
for (const item of data)
{
usedBatchList.value.push(item.id)
allBatchList.value.push(
{
key: item.id,
label: item.name,
}
)
}
}
)
projectApi.getUnusedBatchList().then(
({data}) => {
for (const item of data)
{
allBatchList.value.push(
{
key: item.id,
label: item.name,
}
)
}
}
)
}
const handleMenuSelect = function(index) {
selectedMenuIndex = index
getProjectList()
}
const startProject = function(id) {
ElMessageBox.confirm(
"确定开始项目?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(
() => {
projectApi.startProject(id).then(
(r) => {
const message = r.msg
getProjectList()
ElMessage(`${message}`)
}
)
}
)
}
const finishProject = function(id) {
ElMessageBox.confirm(
"确定结束项目?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(
() => {
projectApi.finishProject(id).then(
(r) => {
const message = r.msg
getProjectList()
ElMessage(`${message}`)
}
)
}
)
}
const getStatusTitle = function(status) {
switch (status)
{
case 0:
{
return '结束中'
}
case 1:
{
return '开始中'
}
default:
{
break
}
}
}
const initialize = function() {
getProjectList()
getCompanyMap(companyMap)
}
initialize()
return {
// scalar
pageNum,
pageSize,
total,
isLoading,
projectList,
ref_addProjectForm,
ref_editProjectForm,
addProjectVisible,
editProjectVisible,
distributeProjectVisible,
distributeBatchVisible,
// sequence
usedBatchList,
allBatchList,
// mapping
companyMap,
addProjectForm,
editProjectForm,
distributeProjectForm,
rules,
// function
handlePageNumChange,
handlePageSizeChange,
addProject,
editProject,
confirmEditProject,
confirmAddProject,
confirmDistributeProject,
distributeProject,
getKeyByValueInObject,
distributeBatch,
handleMenuSelect,
onBatchListChange,
startProject,
finishProject,
getStatusTitle,
}
},
}
</script>
<style lang="less" scoped>
@import "./ProjectManagement.less";
</style>
import {axiosInstance} from '@/Request/PublicAxiosInstance'
import {filterEmptyValueInObject, } from "@/PublicUtil/PublicUtil"
class ProjectApi {
getProjectList(id) {
return axiosInstance.request(
{
method: 'GET',
url: '/tasks',
params: filterEmptyValueInObject(
{
accountId: id
}
)
}
)
}
addProject(data) {
return axiosInstance.request(
{
method: 'POST',
url: '/tasks',
data: filterEmptyValueInObject(
{
name: data.name,
description: data.description,
type: 1,
labelType: 0,
createUser: localStorage.getItem('currentUserId'),
}
)
}
)
}
editProject(id, data) {
return axiosInstance.request(
{
method: 'POST',
url: `/tasks/${id}`,
data: data
}
)
}
finishProject(id) {
return axiosInstance.request(
{
method: 'POST',
url: `/tasks/${id}`,
data: {
status: 0
}
}
)
}
startProject(id) {
return axiosInstance.request(
{
method: 'POST',
url: `/tasks/${id}`,
data: {
status: 1
}
}
)
}
getUsedBatchList(id) {
return axiosInstance.request(
{
method: 'GET',
url: `/packs`,
params: filterEmptyValueInObject(
{
taskId: id
}
)
}
)
}
getUnusedBatchList() {
return axiosInstance.request(
{
method: 'GET',
url: `/packs`,
params: filterEmptyValueInObject(
{
taskId_null: 'true'
}
)
}
)
}
distributeBatch(data) {
return axiosInstance.request(
{
method: 'GET',
url: `/packs/assignTo`,
params: filterEmptyValueInObject(
{
taskId: data.taskId,
packIds: data.packIds,
}
)
}
)
}
cancelDistributeBatch(data) {
return axiosInstance.request(
{
method: 'GET',
url: `/packs/assignTo`,
params: filterEmptyValueInObject(
{
packIds: data.packIds,
}
)
}
)
}
}
const projectApi = new ProjectApi()
export default projectApi
<template>
<el-container class="QualityInspectManagement">
<el-header height="50px">
<div>
<span class="title-text">质检审核</span>
</div>
</el-header>
<el-main>
<el-menu mode="horizontal" @select="handleMenuSelect" :default-active="'1'">
<el-menu-item :index="'1'">
待标注
</el-menu-item>
</el-menu>
<el-table :data="qualityInspectList" v-loading="isLoading">
<el-table-column prop="taskName" label="taskName" align="center"></el-table-column>
<el-table-column prop="packName" label="packName" align="center"></el-table-column>
<el-table-column prop="accountId" label="所属公司" align="center">
<template #default="scope">
{{ companyMap[scope.row.accountId] }}
</template>
</el-table-column>
<el-table-column prop="count" label="count" align="center"></el-table-column>
<el-table-column prop="finishCount" label="finishCount" align="center"></el-table-column>
<el-table-column prop="toBeLabeledCount" label="toBeLabeledCount" align="center"></el-table-column>
<el-table-column prop="operation" label="操作" align="center">
<template #default="scope">
<el-button @click="viewDetails(scope.row.packId)" type="text">查看详情</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</template>
<script>
import {reactive, ref, toRaw,} from "vue"
import {
filterEmptyValueInObject, getKeyByValueInObject,
resetForm
} from "@/PublicUtil/PublicUtil"
import qualityInspectApi from './QualityInspectExamineApi'
import {ElMessageBox} from 'element-plus'
import {ElMessage} from 'element-plus'
import {getCompanyMap} from '@/Request/DictionaryRequest'
import {useRouter} from 'vue-router'
export default {
setup() {
// scalar
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref()
const isLoading = ref(false)
const router = useRouter()
let selectedMenuIndex = '1'
const qualityInspectList = ref([])
// computed
// mapping
const companyMap = reactive({})
// function
const handlePageNumChange = function(num) {
pageNum.value = num
getQualityInspectList()
}
const handlePageSizeChange = function(size) {
pageNum.value = 1
pageSize.value = size
getQualityInspectList()
}
const handleMenuSelect = function(index) {
selectedMenuIndex = index
getQualityInspectList()
}
const viewDetails = function(packId) {
router.push(
{
path: '/DataLabel/PeopleLabel',
query: {
packId: packId,
isReviewAccessed: true,
pageNum: 1,
}
}
)
}
const submitInspect = function(id) {
qualityInspectApi.submitInspect(id).then(
(r) => {
const message = r.msg
ElMessage(
{
message: `${message}`,
}
)
}
)
}
const getQualityInspectList = function() {
isLoading.value = true
qualityInspectApi.getQualityInspectList(selectedMenuIndex).then(
({data}) => {
isLoading.value = false
qualityInspectList.value = data
// formatPaginatedTableData(
// qualityInspectList,
// data,
// total,
// )
}
)
}
const initialize = function() {
getQualityInspectList()
getCompanyMap(companyMap)
}
initialize()
return {
// scalar
pageNum,
pageSize,
total,
isLoading,
qualityInspectList,
// mapping
companyMap,
// function
handlePageNumChange,
handlePageSizeChange,
getKeyByValueInObject,
handleMenuSelect,
viewDetails,
submitInspect,
}
},
}
</script>
<style lang="less" scoped>
@import "./QualityInspectExamine.less";
</style>
import {axiosInstance} from '@/Request/PublicAxiosInstance'
import {filterEmptyValueInObject,} from "@/PublicUtil/PublicUtil"
class QualityInspectApi {
getQualityInspectList(status) {
return axiosInstance.request(
{
method: 'GET',
url: '/packs/info',
params: filterEmptyValueInObject(
{
accountId: localStorage.getItem('currentAccountId'),
status: status,
}
)
}
)
}
submitInspect(id) {
return axiosInstance.request(
{
method: 'POST',
url: `/packs/${id}`,
data: {
status: 1
}
}
)
}
}
const qualityInspectApi = new QualityInspectApi()
export default qualityInspectApi
<template>
<div class="container" ref="container" :style="{ height: containerHeight }">
<div class="empty" :style="{ height: emptyHeight }"></div>
<ul class="list" :style="{ transform: `translateY(${translateY})` }">
<li v-for="item in listData" :key="item" class="item" :style="{ height: itemHeight }">{{ item }}</li>
</ul>
</div>
</template>
<script>
import {computed, onMounted, ref} from 'vue'
export default {
setup() {
const oriData = Array.from({length: 100}, (v, k) => k)
const itemHeight = 20
const emptyHeight = itemHeight * oriData.length
const containerHeight = window.innerHeight
const itemCount = Math.ceil(containerHeight / itemHeight)
const container = ref(null)
const start = ref(0)
const translateY = ref(0)
const listData = computed(() => {
return oriData.slice(start.value, start.value + itemCount + 1)
})
onMounted(
() => {
container.value.addEventListener(
'scroll',
e => {
const {scrollTop} = e.target
start.value = Math.floor(scrollTop / itemHeight)
translateY.value = scrollTop + 'px'
}
)
}
)
return {
listData,
container,
translateY,
containerHeight: containerHeight + 'px',
itemHeight: itemHeight + 'px',
emptyHeight: emptyHeight + 'px'
}
}
}
</script>
<style lang="less" scoped>
.container {
overflow: auto;
display: flex;
}
</style>
.datelevel{
text-align: center;
padding-bottom: 10px;
}
.data-type{
width: 100%;
text-align: center;
}
.data{
width: 100%;
height: 70px;
}
.data-select{
width: 100%;
text-align: center;
margin-top: 0.5%;
}
.button-class{
}
.param{
width: 100%;
text-align: center;
overflow: hidden;
}
.el-select{
width: 310px !important;
}
.el-select__tags{
max-width: 290px !important;
}
.input-class{
width: 200px
}
.face-data{
margin-left: 60px
}
.showData{
/* border-width:5px; */
width: 50%;
height: 460px;
/* border:3px solid gray; */
box-shadow: 0 1px 4px 0 rgba(0,0,0,0.37);
border-radius: 4px;
margin: 0 auto;
position: relative;
/* left: 50%;
margin-left: -25%; */
overflow: auto;
}
.show-span{
margin-left: 10px;
}
.clear-select{
text-align: center;
padding: 10px 0 10px 0;
}
.date-time{
height: 30px;
}
/*覆盖 element css*/
.el-input__inner {
height: 30px !important;
line-height: 30px !important;
}
.el-input__icon {
line-height: 30px !important;
}
.date-time .el-input__inner {
height: 30px !important;
line-height: 30px !important;
}
.date-time .el-input__icon {
line-height: 30px !important;
}
.el-button {
padding: 6px 20px !important;
}
.input-class {
width: 200px
}
.date-select {
width: 100%;
text-align: center;
padding: 5px;
}
/* 全選 */
.mall-sel-box {
/* display: block; */
height: 22px;
font-size: 13px;
width: 150px;
height: 100%;
}
.sel-all-box {
height: 30px;
line-height: 30px;
font-size: 14px;
padding: 0 20px;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #606266;
box-sizing: border-box;
cursor: pointer;
}
.sel-all-box.selected {
color: #409EFF;
font-weight: 700;
background-color: #fff;
}
.sel-all-box.selected .custom-checkbox__inner {
background-color: #409eff;
border-color: #409eff;
}
.sel-all-box.selected .custom-checkbox__inner:after {
transform: rotate(45deg) scaleY(1);
}
.custom-checkbox__input {
white-space: nowrap;
cursor: pointer;
outline: none;
display: inline-block;
line-height: 1;
position: relative;
vertical-align: middle;
}
.custom-checkbox__inner {
display: inline-block;
position: relative;
border: 1px solid #dcdfe6;
border-radius: 2px;
box-sizing: border-box;
width: 14px;
height: 14px;
background-color: #fff;
z-index: 1;
transition: border-color .05s cubic-bezier(.71, -.46, .29, 1.46), background-color .05s cubic-bezier(.71, -.46, .29, 1.46);
}
.custom-checkbox__inner:after {
box-sizing: content-box;
content: "";
border: 1px solid #fff;
border-left: 0;
border-top: 0;
height: 7px;
left: 4px;
position: absolute;
top: 1px;
transform: rotate(45deg) scaleY(0);
width: 3px;
transition: transform .05s cubic-bezier(.71, -.46, .88, .6) .05s;
transform-origin: center;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after {
content: none;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected .custom-checkbox__inner {
background-color: #409eff;
border-color: #409eff;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected .custom-checkbox__inner:after {
transform: rotate(45deg) scaleY(1);
}
.center-div {
position: absolute;
left: 50%;
margin-left: -12%;
}
.center-progress {
display: inline-block;
margin-left: 38%;
}
.center-repairprogress {
display: inline-block;
}
.check-box {
}
.top-box {
}
.el-checkbox-group {
padding-top: 1px;
}
.el-checkbox:first-child {
margin-left: 55px
}
.el-checkbox+.el-checkbox {
margin-left: 70px;
}
.el-checkbox:last-child {
margin-left: 75px
}
.el-checkbox {
padding: 1px 0 1px 0;
}
.el-checkbox__inner{
width: 15px;
height: 15px;
}
.el-checkbox__label {
font-size: 16px
}
.level-div {
font-size: 18px;
padding: 0px 0px 0px 30px;
}
.level-box :first-child{
padding-top: 22px;
}
.bloc-mall-box {
text-align: center;
width: 50%;
float: left;
}
.line-progress {
display: block;
width: 405px;
background-color: #ebeef5;
height: 18px;
border-radius: 20px;
margin-left: 50px;
margin-top: -20px;
}
.websocket-line {
height: 18px;
/* border-radius: 20px; */
margin-left: 50px;
margin-top: -18px;
background-color: #409EFF;
position: relative;
z-index: 999;
}
.check-box .websocket-line:nth-of-type(1) {
border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
}
.check-box .websocket-line:nth-of-type(2) {
border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
}
.check-box :last-child {
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
}
.tooltip-div {
height:50px;
background-color: #fff;
position:absolute;
z-index: 9999;
text-align: center;
border:2px solid black;
border-radius: 10px;
}
No preview for this file type
This diff could not be displayed because it is too large.
[v-cloak] {
display: none;
}
html, body, #app {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.container {
width: 100%;
height: 100%;
padding-top: 10px;
max-width: 1200px;
margin: 0 auto;
box-sizing: border-box;
}
.query-box {
width: 100%;
display: table;
}
.query-box + .query-box {
padding-top: 10px;
}
.query-item {
display: table-cell;
text-align: right;
width: 50%;
}
.query-item+.query-item {
padding-left: 20px;
text-align: left;
}
.query-select {
font-size: 13px;
}
.query-item__title {
font-size: 14px;
}
.query-button {
margin-left: 20px;
}
.showData{
width: 50%;
height: 460px;
min-width: 600px;
box-shadow: 0 1px 4px 0 rgba(0,0,0,0.37);
border-radius: 4px;
margin: 0 auto;
position: relative;
overflow: auto;
}
.result-wrapper {
/* padding: 0 20px; */
width: 50%;
min-width: 600px;
box-shadow: 0 1px 4px 0 rgba(0,0,0,0.37);
border-radius: 4px;
margin: 20px auto 0;
position: relative;
overflow: auto;
}
.result-header {
text-align: center;
font-size: 16px;
padding: 10px 0;
box-shadow: 0px 0px 3px 0 rgba(0,0,0,.2);
/* margin: 10px 0 0; */
}
.result-content {
font-size: 14px;
padding: 0 20px 20px;
}
.result-item {
padding-right: 8px;
box-sizing: border-box;
}
.result-item + .result-item {
margin-top: 10px;
}
.empty-data {
text-align: center;
padding: 10px 0;
font-size: 14px;
}
.result-page {
margin: 8px 0;
}
.result-page span + .result-page span {
padding: 0 5px;
}
/* .result-progress-wrapper {
margin: 20px 0 10px;
} */
.result-progress-wrapper::after,
.result-progress-wrapper::before {
content: '';
display: table;
}
.result-progress-wrapper::after {
clear: both;
}
.result-progress-left {
float: left;
}
.result-progress-right {
width: 100%;
padding-left: 88px;
box-sizing: border-box;
}
.result-progress {
height: 26px;
margin-bottom: 4px;
position: relative;
border-radius: 100px;
/* box-shadow: 0px 0px 2px 0 rgba(0,0,0,1); */
background-color: #ebeef5;
overflow: hidden;
}
.result-progress__inner {
width: 0;
position: absolute;
left: 0;
top: 0;
height: 100%;
color: #fff;
background: #409EFF;
/* background-image: linear-gradient(#86bef7, #409eff); */
border-radius: inherit;
text-align: right;
transition: width 0.1s linear;
}
.result-progress__text {
display: inline-block;
margin: 0 5px;
vertical-align: middle;
}
.result-progress-right span {
padding-left: 10px;
}
.pagination-page {
float: right;
padding-right: 10px;
}
.result-footer {
padding: 12px 20px;
font-size: 16px;
box-shadow: 0px 0px 3px 0 rgba(0,0,0,.2);
}
.result-footer::after,
.result-footer::before {
content: '';
display: table;
}
.result-footer::after {
clear: both;
}
.result-intro {
float: left;
}
.result-clear-btn {
float: right;
border-radius: 20px;
}
/* login */
#loginApp {
width: 100%;
height: 100%;
}
.login-container {
width: 100%;
height: 100%;
background: url(../image/login_bg.png) no-repeat;
background-size: 100% 100%;
text-align: right;
}
.login-form {
display: inline-block;
width: 20%;
padding-top: 30vh;
margin-right: 10%;
color: #fff;
box-sizing: border-box;
}
.login-title {
text-align: left;
}
input::-webkit-autofill {
background-color: transparent;
box-shadow: 0 0 0 1000px rgba(255, 255, 255, 0) inset !important;
-webkit-box-shadow: 0 0 0 1000px rgba(255, 255, 255, 0) inset !important;
-webkit-text-fill-color: #fff !important;
transition: background-clor 5000s ease-in-out 0s;
}
@keyframes move {
0% {
background-position: 0 0;
}
100% {
background-position: 30px 30px;
}
}
/* cover elementui stylesheet*/
.scrollbar-wrapper {
height: 100%;
height: 376px;
max-height: 376px;
overflow-x: hidden !important;
}
.el-scrollbar__bar.is-vertical {
right: 0px;
}
.el-scrollbar {
height: 100%;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<!-- import CSS -->
<link rel="stylesheet" href="./css/index.css"/>
<link rel="stylesheet" href="./css/common.css">
<link rel="stylesheet" href="./css/page.css">
<script src="./js/browser.min.js"></script>
</head>
<body>
<div id="app" v-cloak>
<div class="container">
<div class="datelevel">
<el-radio-group v-model="dateFormat" @change="dateLevel">
<el-radio-button
v-for="item in dateLevelList"
:key="item.label"
:label="item.label"
>{{ item.name }}
</el-radio-button>
<el-radio-button label="compare" v-if="locationHref">数据比对</el-radio-button>
</el-radio-group>
</div>
<div v-show="dateFormat === 'rerun'">
<div class="param">
<div class="bloc-mall-box">
<div style="float: right;">
<span>集团:</span>
<el-select
v-model="accountVal"
filterable
multiple
collapse-tags
clearable
placeholder="请选择集团"
class="mall-sel-box"
@change="accountchange"
>
<div
:class="isAccoutSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle('accout')"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in accoutOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
<div class="bloc-mall-box">
<div style="float: left;margin-left:2%;">
<span>商场:</span>
<el-select
v-model="mallVal"
filterable
multiple
collapse-tags
clearable
placeholder="请选择商场"
class="mall-sel-box"
@change="mallchange"
>
<div
:class="isMallSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle()"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in mallOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
</div>
<div class="param" style="padding: 5px 0 15px;">
<div class="bloc-mall-box">
<div style="float: right;margin-right: 50px;">
<span>开始日期:</span>
<el-date-picker
v-model="startTime"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOpts"
placeholder="选择开始日期"
>
</el-date-picker>
</div>
</div>
<div class="bloc-mall-box">
<div style="float: left;margin-left:2%;">
<span>结束日期:</span>
<el-date-picker
v-model="endTime"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOpts"
placeholder="选择结束日期"
>
</el-date-picker>
</div>
</div>
</div>
<div class="data">
<div class="center-div">
<div class="top-box">
<span class="level-div">商场/门店</span>
<span class="level-div">楼层</span>
<span class="level-div">店铺/区域</span>
<span class="level-div">监控点</span>
</div>
<div class="check-box">
<span
style="position: absolute;margin-left: -50px;font-size:18px"
>客流数据:</span
>
<el-checkbox
style="position:absolute;margin-left:400px"
:indeterminate="isIndeterminateTraffic"
v-model="checkAllTraffic"
@change="handleCheckAllChangeTraffic"
>全选
</el-checkbox
>
<el-checkbox-group
v-model="checkedTraffic"
@change="handleCheckedCitiesChangeTraffic"
>
<el-checkbox
v-for="item in checkTraffic"
:label="item.value"
:key="item.value"
>{{item.name}}
</el-checkbox
>
</el-checkbox-group>
</div>
<div class="check-box">
<span
style="position: absolute;margin-left: -50px;font-size:18px"
>人脸数据:</span
>
<el-checkbox
style="position:absolute;margin-left:400px;padding-top:2px"
:indeterminate="isIndeterminateFace"
v-model="checkAllFace"
@change="handleCheckAllChangeFace"
>全选
</el-checkbox
>
<el-checkbox-group
style="padding-top:3px"
v-model="checkedFace"
@change="handleCheckedCitiesChangeFace"
>
<el-checkbox
v-for="item in checkFace"
:label="item.value"
:key="item.value"
>{{item.name}}
</el-checkbox
>
</el-checkbox-group>
</div>
<el-button
style="position: absolute;margin-left: 480px;margin-top: -38px;"
size="small"
round
@click="startData()"
class="button-class"
>开始
</el-button
>
</div>
<div></div>
</div>
<div style="width: 100%;padding-top: 20px;">
<div class="center-progress">
<div class="check-box" v-for="item in progressList">
<span style="margin-left: -50px;font-size:18px"
>{{ getProgressName(item.stepType) }}:</span
>
<span :style="getProgressStyle('stepType',item.stepType)"
>{{ item.precentsucess ? item.precentsucess + '%' : 0 +
'%'}}</span
>
<span class="line-progress"></span>
<div
class="websocket-line"
@mouseover="lineOver($event,item1.dates,item1.mallIds,item1.mallNames)"
@mouseout="lineOut()"
v-for="(item1,index) in item.stepList "
:style="getProgressStyle(item1.stepCount,item1.status,item.stepList[index ? index-1 : index].stepCount)"
></div>
</div>
</div>
</div>
</div>
<div v-show="dateFormat === 'repair'">
<div class="data-type">
<div class="level">
<el-radio-group v-model="UrlType" size="small">
<el-radio-button label="trafficRecognition"
>客流数据
</el-radio-button
>
<el-radio-button label="faceRecognitions"
>人脸数据
</el-radio-button
>
</el-radio-group>
</div>
<div v-show="UrlType == 'faceRecognitions'">
<div class="data-select">
<span>集团:</span>
<el-select
v-model="accountVal"
filterable
multiple
collapse-tags
clearable
placeholder="请选择集团"
class="mall-sel-box"
@change="accountchange(true)"
>
<div
:class="isAccoutSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle('accout')"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in accoutOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
<span>商场/门店:</span>
<el-select
v-model="mallVal"
filterable
multiple
collapse-tags
clearable
placeholder="请选择商场"
class="mall-sel-box"
@change="mallchange(true)"
>
<div
:class="isMallSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle()"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in mallOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
<div class="data-select">
<span>监控点名称:</span>
<el-select
v-model="gateVal"
filterable
clearable
placeholder="请选择监控点"
@change="getChannel"
>
<el-option
v-for="(item, index) in gateOpt"
:key="item.index"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
<span>设备序列号:</span>
<!-- <el-select v-model="deviceVal" filterable clearable placeholder="请选择设备序列号">
<el-option v-for="(item, index) in deviceOpt" :key="index" :label="item.name" :value="item.value">
</el-option>
</el-select> -->
<el-select
v-model="channelVal"
filterable
clearable
placeholder="请选择通道设备序列号"
>
<el-option
v-for="item in channelOpt"
:key="item.id"
:label="item.name"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div class="data-select">
<span>源数据日期:</span>
<el-date-picker
v-model="sourceDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
>
</el-date-picker>
<span>开始时间:</span>
<el-time-picker
v-model="sourceStartTime"
placeholder="选择开始时间"
value-format="HH:mm:ss"
>
</el-time-picker>
<span>结束时间:</span>
<el-time-picker
v-model="sourceEndTime"
placeholder="选择结束时间"
value-format="HH:mm:ss"
>
</el-time-picker>
</div>
<div class="data-select">
<span style="margin-left: -14px;">目标数据日期:</span>
<el-date-picker
v-model="aimsDate"
type="date"
placeholder="选择日期时间"
value-format="yyyy-MM-dd"
class="date-time"
>
</el-date-picker>
<span>开始时间:</span>
<el-time-picker
v-model="aimsStartTime"
placeholder="选择开始时间"
value-format="HH:mm:ss"
>
</el-time-picker>
<span>结束时间:</span>
<el-time-picker
v-model="aimsEndTime"
placeholder="选择结束时间"
value-format="HH:mm:ss"
>
</el-time-picker>
</div>
<div class="data-select">
<el-button
type="primary"
:loading="butShow"
@click="getDateCount"
>源数据条数查询
</el-button
>
<span>数量:</span>
<el-input
v-model="dateCount"
placeholder="显示条数"
class="input-class"
disabled
></el-input>
<span>修补条数:</span>
<el-input
v-model="count"
placeholder="请输入条数"
value="number"
class="input-class"
></el-input>
<el-button
type="primary"
:loading="startShow"
@click="repairParams('face')"
>开始修补
</el-button
>
</div>
<div style="width: 100%;padding-top: 20px;">
<div class="center-repairprogress">
<div class="check-box" v-for="item in repairProgList">
<span style="margin-left: -40px;font-size:18px"
>修补进度:</span
>
<span style="margin-left: 430px;font-size: 18px"
>{{ item.precentsucess ? item.precentsucess + '%' : 0 +
'%'}}</span
>
<span class="line-progress"></span>
<div
class="websocket-line"
v-for="(item1,index) in item.stepList "
:style="getProgressStyle(item1.stepCount,item1.status,item.stepList[index ? index-1 : index].stepCount)"
></div>
</div>
</div>
</div>
</div>
</div>
<div v-show="UrlType == 'trafficRecognition'" class="data-type">
<div class="data-select">
<span>集团:</span>
<el-select
v-model="accountVal"
filterable
multiple
collapse-tags
clearable
placeholder="请选择集团"
class="mall-sel-box"
@change="accountchange"
>
<div
:class="isAccoutSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle('accout')"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in accoutOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
<span>商场/门店:</span>
<el-select
v-model="mallVal"
filterable
multiple
collapse-tags
clearable
placeholder="请选择商场"
class="mall-sel-box"
@change="mallchange"
>
<div
:class="isMallSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle()"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in mallOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
<div class="data-select">
<span>监控点名称:</span>
<el-select
v-model="gateVal"
filterable
clearable
placeholder="请选择监控点"
@change="getChannel"
>
<el-option
v-for="(item, index) in gateOpt"
:key="item.index"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
<span>通道设备序列号:</span>
<el-select
v-model="channelVal"
filterable
clearable
placeholder="请选择通道设备序列号"
>
<el-option
v-for="item in channelOpt"
:key="item.id"
:label="item.name"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div class="data-select">
<span>修补日期:</span>
<el-date-picker
v-model="repairDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
>
</el-date-picker>
<span>参考日期:</span>
<el-date-picker
v-model="referenceDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
>
</el-date-picker>
</div>
<div class="data-select">
<span>开始时间:</span>
<el-time-picker
v-model="traffStartTime"
value-format="HH:mm:ss"
placeholder="开始时间"
>
</el-time-picker>
<span>结束时间:</span>
<el-time-picker
v-model="traffEndTime"
value-format="HH:mm:ss"
placeholder="结束时间"
>
</el-time-picker>
</div>
<div class="data-select">
<span>数据计算范围:</span>
<el-input
v-model="startRange"
placeholder="请输入计算范围"
value="number"
class="input-class"
></el-input>
<el-input
v-model="endRange"
placeholder="请输入计算范围"
value="number"
class="input-class"
></el-input>
</div>
<div class="data-select" style="margin-top: 0.8%;">
<el-button type="primary" @click="repairPreview"
>效果预览
</el-button
>
<el-button
type="primary"
:loading="tafficShow"
@click="repairParams"
>开始修补
</el-button
>
</div>
<div style="width: 100%;padding-top: 20px;">
<div class="center-repairprogress">
<div class="check-box" v-for="item in repairProgList">
<span style="margin-left: -40px;font-size:18px"
>修补进度:</span
>
<span style="margin-left: 430px;font-size: 18px"
>{{ item.precentsucess ? item.precentsucess + '%' : 0 +
'%'}}</span
>
<span class="line-progress"></span>
<div
class="websocket-line"
v-for="(item1,index) in item.stepList "
:style="getProgressStyle(item1.stepCount,item1.status,item.stepList[index ? index-1 : index].stepCount)"
></div>
</div>
</div>
</div>
</div>
</div>
<!-- repair end -->
<div v-show="dateFormat === 'compare'">
<div class="data-type">
<div class="level" style="margin-bottom: 10px">
<el-radio-group
v-model="compareType"
size="small"
@change="getNumber"
>
<el-radio-button label="custom">顾客比对</el-radio-button>
<el-radio-button label="staff">店员比对</el-radio-button>
</el-radio-group>
</div>
<div class="param">
<div class="bloc-mall-box">
<div style="float: right;">
<span style="font-size:20px;">集团:</span>
<el-select
v-model="accountVal"
filterable
multiple
collapse-tags
clearable
placeholder="请选择集团"
class="mall-sel-box"
@change="accountchange"
>
<div
:class="isAccoutSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle('accout')"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in accoutOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
<div class="bloc-mall-box">
<div style="float: left;margin-left:2%;">
<span style="font-size:20px;">商场:</span>
<el-select
v-model="mallVal"
filterable
multiple
collapse-tags
clearable
placeholder="请选择商场"
class="mall-sel-box"
@change="mallchange"
>
<div
:class="isMallSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle()"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in mallOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
</div>
<div class="param" style="padding: 5px 0 15px;">
<div class="bloc-mall-box">
<div style="float: right;margin-right: 50px;">
<span style="font-size:20px;">开始日期:</span>
<el-date-picker
v-model="startTime"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOpts"
placeholder="选择开始日期"
>
</el-date-picker>
</div>
</div>
<div class="bloc-mall-box">
<div style="float: left;margin-left:2%;">
<span style="font-size:20px;">结束日期:</span>
<el-date-picker
v-model="endTime"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOpts"
placeholder="选择结束日期"
>
</el-date-picker>
</div>
</div>
<el-button type="primary" @click="compareParams"
>开始比对
</el-button
>
</div>
</div>
</div>
<!-- compare end -->
<div v-show="dateFormat === 'revisitFeature'">
<div class="query-box">
<div class="query-item">
<span class="query-item__title">集团 : </span>
<el-select
v-model="accountVal"
filterable
multiple
collapse-tags
:clearable="false"
placeholder="请选择集团"
class="query-select mall-sel-box"
@change="accountchange"
>
<div
:class="isAccoutSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle('accout')"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in accoutOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
<div class="query-item">
<span class="query-item__title">商场/门店 : </span>
<el-select
v-model="mallVal"
filterable
multiple
collapse-tags
:clearable="false"
placeholder="请选择商场"
class="query-select mall-sel-box"
@change="mallchange"
>
<div
:class="isMallSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle()"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in mallOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
<div class="query-box">
<div class="query-item">
<span class="query-item__title">特征重提类型 : </span>
<el-select
v-model="featureRevisitType"
placeholder="请选择类型"
class="query-select query-select__type"
>
<el-option
v-for="item in featureRevisitList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
<div class="query-item">
<span v-show="isSendDateParam" class="query-item__title">日期 : </span>
<el-date-picker
v-show="isSendDateParam"
v-model="query.dateVal"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOpts"
placeholder="选择日期"
></el-date-picker>
<el-button
type="primary"
:class="isSendDateParam ? '' : 'query-button'"
@click="onSearchClick"
>开 始
</el-button>
</div>
</div>
</div>
<!-- revisitFeature end -->
<div v-show="dateFormat === 'rebuildFeatureLib'">
<div class="query-box">
<div class="query-item">
<span class="query-item__title">集团 : </span>
<el-select
v-model="accountVal"
filterable
multiple
collapse-tags
:clearable="false"
placeholder="请选择集团"
class="query-select mall-sel-box"
@change="accountchange"
>
<div
:class="isAccoutSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle('accout')"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in accoutOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
<div class="query-item">
<span class="query-item__title">商场/门店 : </span>
<el-select
v-model="mallVal"
filterable
multiple
collapse-tags
:clearable="false"
placeholder="请选择商场"
class="query-select mall-sel-box"
@change="mallchange"
>
<div
:class="isMallSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle()"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in mallOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
<div class="query-box">
<div class="query-item">
<span class="query-item__title">特征池重建类型 : </span>
<el-select
v-model="featureLibRebuildType"
placeholder="请选择类型"
class="query-select query-select__type"
>
<el-option
v-for="item in featureLibRebuildList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
<div class="query-item">
<span v-show="isSendDateParam" class="query-item__title">日期 : </span>
<el-date-picker
v-show="isSendDateParam"
v-model="query.dateVal"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOpts"
placeholder="选择日期"
></el-date-picker>
<el-button type="primary" :class="isSendDateParam ? '' : 'query-button'" @click="onSearchClick">开 始</el-button>
</div>
</div>
</div>
<!-- rebuildFeatureLib end -->
<div v-show="dateFormat === 'rematchPerson'">
<!-- 人员重新比对 -->
<div class="query-box">
<div class="query-item">
<span class="query-item__title">集团 : </span>
<el-select
v-model="accountVal"
filterable
multiple
collapse-tags
:clearable="false"
placeholder="请选择集团"
class="query-select"
@change="accountchange"
>
<div
:class="isAccoutSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle('accout')"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in accoutOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
<div class="query-item">
<span class="query-item__title">商场/门店 : </span>
<el-select
v-model="mallVal"
filterable
multiple
collapse-tags
:clearable="false"
placeholder="请选择商场"
class="query-select"
@change="mallchange"
>
<div
:class="isMallSelAll ? 'sel-all-box selected' : 'sel-all-box'"
@click="selAllHandle()"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">全选</span>
</div>
<el-option
v-for="item in mallOpts"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
<div class="query-box">
<div class="query-item">
<span class="query-item__title">比对类型 : </span>
<el-select
v-model="rematchPersonType"
placeholder="请选择类型"
class="query-select query-select__type"
>
<el-option
v-for="item in rematchPersonList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
<div class="query-item">
<span class="query-item__title">日期 : </span>
<el-date-picker
v-model="query.dateVal"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOpts"
placeholder="选择日期"
></el-date-picker>
<el-button type="primary" class="query-button" @click="onSearchClick">开 始</el-button>
</div>
</div>
</div>
<div v-show="dateFormat === 'snapGatherClass'">
<el-menu mode="horizontal" mode="horizontal" @select="onMenuSelect" :default-active="'1'">
<el-menu-item :index="'1'">
抓拍结果
</el-menu-item>
<el-menu-item :index="'2'">
聚类结果
</el-menu-item>
</el-menu>
<div v-if="currentIndex6 === '1'">
<el-form :inline="true" size="small">
<el-form-item label="平台:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="集团:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="广场:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="出入类型:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="门店:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="监控点:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="方向:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="抓拍类型:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="人员类型:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="选择日期:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
</el-form>
<el-button type="primary">搜索</el-button>
</div>
<div v-if="currentIndex6 === '2'">
<el-form :inline="true" size="small">
<el-form-item label="平台:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="集团:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="广场:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="出入类型:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="门店:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="监控点:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="方向:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="抓拍类型:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="人员类型:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="选择日期:">
<el-select>
<el-option :label="'Store'"></el-option>
<el-option :label="'Mall'"></el-option>
</el-select>
</el-form-item>
</el-form>
<el-button type="primary">搜索</el-button>
</div>
</div>
<!-- <div class="clear-select">
<el-button size="small" round @click="clearDiv()">清空Div</el-button>
</div> -->
<div v-show="dateFormat !== 'snapGatherClass'" class="result-wrapper">
<div class="result-header">结果展示</div>
<el-scrollbar ref="scrollbarRef" wrap-class="scrollbar-wrapper">
<div id="showDiv" class="result-content" v-show="showDiv">
<!-- /{{ item.totalNum }}条 -->
<div v-if="isResultsShow && !results.length" class="empty-data">数据为空~</div>
<div class="result-item" v-for="item in results" :key="item.id">
<!-- /{{ item.totalNum }}条 -->
<div class="result-page">
<span>总处理条数 : {{ item.totalNum }}条</span>
</div>
<div class="result-progress-wrapper">
<span class="result-progress-left">执行进度 : </span>
<div class="result-progress-right">
<div class="result-progress">
<div class="result-progress__inner" :class="item.progress <= 100 ? 'move-animate' : ''" :style="{ width: item.progress + '%' }">
<div class="result-progress__text">{{ item.progress + '%' }}</div>
</div>
</div>
<span>第{{ item.current }}条/共{{ item.curPageSize }}条</span>
<span class="pagination-page">第{{ item.currentPage }}页/共{{ item.totalPage }}页</span>
</div>
</div>
</div>
</div>
</el-scrollbar>
<div class="result-footer">
<span class="result-intro" v-if="startTiming && endTiming">{{ footerText || '数据重跑' }}完毕! 共计 {{ totalTime | formatTime }}</span>
<el-button class="result-clear-btn" @click="onClearClick">清空结果</el-button>
</div>
</div>
<div v-show="tipShow" class="tooltip-div" :style="tipStyle">
<div>
<span>商场Id:</span><span>{{ lineMallId }}</span
><span> 商场名称:</span><span>{{ lineMallName }}</span>
</div>
<div><span>时间:</span><span>{{ lineDate }}</span></div>
</div>
</div>
</div>
<script src="./js/cookie.js"></script>
<!-- import Vue before Element -->
<script src="./js/vue.js"></script>
<!-- import JavaScript -->
<script src="./js/index.js"></script>
<script src="./js/axios.js"></script>
<script
src="./js/jquery-3.1.0.min.js"
type="text/javascript"
charset="utf-8"
></script>
<script src="./js/common.js" type="text/javascript" charset="utf-8"></script>
<script src="./js/request.js"></script>
<script src="./js/api.js"></script>
<script src="./js/home.js"></script>
</body>
</html>
const API = {
Login: '/users/login',
Accounts: '/accounts',
Malls: '/malls',
Gates: '/gates',
Devices: '/devices',
Channels: '/channels',
Mall: '/mall/',
FaceRecognitionsCount: '/faceRecognitions/count',
SimulationFaceRecognition: '/simulation/faceRecognition',
SimulationCountData: '/simulation/countData',
PreviewCountData: '/preview/countData',
mallStaffFeature: '/mall/staffFeature',
MallFeature: '/mall/feature',
MallStaffPool: '/mall/staffPool',
MallCustomPool: '/mall/customPool',
MallStaff: '/mall/staff',
MallCustom: '/mall/custom'
}
const WSAPI = {
RecalSchedule: '/recal/schedule/'
}
/* axios v0.19.2 | (c) 2020 by Matt Zabriskie */
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["axios"] = factory();
else
root["axios"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
var bind = __webpack_require__(3);
var Axios = __webpack_require__(4);
var mergeConfig = __webpack_require__(22);
var defaults = __webpack_require__(10);
/**
* Create an instance of Axios
*
* @param {Object} defaultConfig The default config for the instance
* @return {Axios} A new instance of Axios
*/
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
var instance = bind(Axios.prototype.request, context);
// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context);
// Copy context to instance
utils.extend(instance, context);
return instance;
}
// Create the default instance to be exported
var axios = createInstance(defaults);
// Expose Axios class to allow class inheritance
axios.Axios = Axios;
// Factory for creating new instances
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
// Expose Cancel & CancelToken
axios.Cancel = __webpack_require__(23);
axios.CancelToken = __webpack_require__(24);
axios.isCancel = __webpack_require__(9);
// Expose all/spread
axios.all = function all(promises) {
return Promise.all(promises);
};
axios.spread = __webpack_require__(25);
module.exports = axios;
// Allow use of default import syntax in TypeScript
module.exports.default = axios;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var bind = __webpack_require__(3);
/*global toString:true*/
// utils is a library of generic helper functions non-specific to axios
var toString = Object.prototype.toString;
/**
* Determine if a value is an Array
*
* @param {Object} val The value to test
* @returns {boolean} True if value is an Array, otherwise false
*/
function isArray(val) {
return toString.call(val) === '[object Array]';
}
/**
* Determine if a value is undefined
*
* @param {Object} val The value to test
* @returns {boolean} True if the value is undefined, otherwise false
*/
function isUndefined(val) {
return typeof val === 'undefined';
}
/**
* Determine if a value is a Buffer
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a Buffer, otherwise false
*/
function isBuffer(val) {
return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
&& typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val);
}
/**
* Determine if a value is an ArrayBuffer
*
* @param {Object} val The value to test
* @returns {boolean} True if value is an ArrayBuffer, otherwise false
*/
function isArrayBuffer(val) {
return toString.call(val) === '[object ArrayBuffer]';
}
/**
* Determine if a value is a FormData
*
* @param {Object} val The value to test
* @returns {boolean} True if value is an FormData, otherwise false
*/
function isFormData(val) {
return (typeof FormData !== 'undefined') && (val instanceof FormData);
}
/**
* Determine if a value is a view on an ArrayBuffer
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
*/
function isArrayBufferView(val) {
var result;
if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
result = ArrayBuffer.isView(val);
} else {
result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer);
}
return result;
}
/**
* Determine if a value is a String
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a String, otherwise false
*/
function isString(val) {
return typeof val === 'string';
}
/**
* Determine if a value is a Number
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a Number, otherwise false
*/
function isNumber(val) {
return typeof val === 'number';
}
/**
* Determine if a value is an Object
*
* @param {Object} val The value to test
* @returns {boolean} True if value is an Object, otherwise false
*/
function isObject(val) {
return val !== null && typeof val === 'object';
}
/**
* Determine if a value is a Date
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a Date, otherwise false
*/
function isDate(val) {
return toString.call(val) === '[object Date]';
}
/**
* Determine if a value is a File
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a File, otherwise false
*/
function isFile(val) {
return toString.call(val) === '[object File]';
}
/**
* Determine if a value is a Blob
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a Blob, otherwise false
*/
function isBlob(val) {
return toString.call(val) === '[object Blob]';
}
/**
* Determine if a value is a Function
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a Function, otherwise false
*/
function isFunction(val) {
return toString.call(val) === '[object Function]';
}
/**
* Determine if a value is a Stream
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a Stream, otherwise false
*/
function isStream(val) {
return isObject(val) && isFunction(val.pipe);
}
/**
* Determine if a value is a URLSearchParams object
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a URLSearchParams object, otherwise false
*/
function isURLSearchParams(val) {
return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
}
/**
* Trim excess whitespace off the beginning and end of a string
*
* @param {String} str The String to trim
* @returns {String} The String freed of excess whitespace
*/
function trim(str) {
return str.replace(/^\s*/, '').replace(/\s*$/, '');
}
/**
* Determine if we're running in a standard browser environment
*
* This allows axios to run in a web worker, and react-native.
* Both environments support XMLHttpRequest, but not fully standard globals.
*
* web workers:
* typeof window -> undefined
* typeof document -> undefined
*
* react-native:
* navigator.product -> 'ReactNative'
* nativescript
* navigator.product -> 'NativeScript' or 'NS'
*/
function isStandardBrowserEnv() {
if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' ||
navigator.product === 'NativeScript' ||
navigator.product === 'NS')) {
return false;
}
return (
typeof window !== 'undefined' &&
typeof document !== 'undefined'
);
}
/**
* Iterate over an Array or an Object invoking a function for each item.
*
* If `obj` is an Array callback will be called passing
* the value, index, and complete array for each item.
*
* If 'obj' is an Object callback will be called passing
* the value, key, and complete object for each property.
*
* @param {Object|Array} obj The object to iterate
* @param {Function} fn The callback to invoke for each item
*/
function forEach(obj, fn) {
// Don't bother if no value provided
if (obj === null || typeof obj === 'undefined') {
return;
}
// Force an array if not already something iterable
if (typeof obj !== 'object') {
/*eslint no-param-reassign:0*/
obj = [obj];
}
if (isArray(obj)) {
// Iterate over array values
for (var i = 0, l = obj.length; i < l; i++) {
fn.call(null, obj[i], i, obj);
}
} else {
// Iterate over object keys
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
fn.call(null, obj[key], key, obj);
}
}
}
}
/**
* Accepts varargs expecting each argument to be an object, then
* immutably merges the properties of each object and returns result.
*
* When multiple objects contain the same key the later object in
* the arguments list will take precedence.
*
* Example:
*
* ```js
* var result = merge({foo: 123}, {foo: 456});
* console.log(result.foo); // outputs 456
* ```
*
* @param {Object} obj1 Object to merge
* @returns {Object} Result of all merge properties
*/
function merge(/* obj1, obj2, obj3, ... */) {
var result = {};
function assignValue(val, key) {
if (typeof result[key] === 'object' && typeof val === 'object') {
result[key] = merge(result[key], val);
} else {
result[key] = val;
}
}
for (var i = 0, l = arguments.length; i < l; i++) {
forEach(arguments[i], assignValue);
}
return result;
}
/**
* Function equal to merge with the difference being that no reference
* to original objects is kept.
*
* @see merge
* @param {Object} obj1 Object to merge
* @returns {Object} Result of all merge properties
*/
function deepMerge(/* obj1, obj2, obj3, ... */) {
var result = {};
function assignValue(val, key) {
if (typeof result[key] === 'object' && typeof val === 'object') {
result[key] = deepMerge(result[key], val);
} else if (typeof val === 'object') {
result[key] = deepMerge({}, val);
} else {
result[key] = val;
}
}
for (var i = 0, l = arguments.length; i < l; i++) {
forEach(arguments[i], assignValue);
}
return result;
}
/**
* Extends object a by mutably adding to it the properties of object b.
*
* @param {Object} a The object to be extended
* @param {Object} b The object to copy properties from
* @param {Object} thisArg The object to bind function to
* @return {Object} The resulting value of object a
*/
function extend(a, b, thisArg) {
forEach(b, function assignValue(val, key) {
if (thisArg && typeof val === 'function') {
a[key] = bind(val, thisArg);
} else {
a[key] = val;
}
});
return a;
}
module.exports = {
isArray: isArray,
isArrayBuffer: isArrayBuffer,
isBuffer: isBuffer,
isFormData: isFormData,
isArrayBufferView: isArrayBufferView,
isString: isString,
isNumber: isNumber,
isObject: isObject,
isUndefined: isUndefined,
isDate: isDate,
isFile: isFile,
isBlob: isBlob,
isFunction: isFunction,
isStream: isStream,
isURLSearchParams: isURLSearchParams,
isStandardBrowserEnv: isStandardBrowserEnv,
forEach: forEach,
merge: merge,
deepMerge: deepMerge,
extend: extend,
trim: trim
};
/***/ }),
/* 3 */
/***/ (function(module, exports) {
'use strict';
module.exports = function bind(fn, thisArg) {
return function wrap() {
var args = new Array(arguments.length);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
return fn.apply(thisArg, args);
};
};
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
var buildURL = __webpack_require__(5);
var InterceptorManager = __webpack_require__(6);
var dispatchRequest = __webpack_require__(7);
var mergeConfig = __webpack_require__(22);
/**
* Create a new instance of Axios
*
* @param {Object} instanceConfig The default config for the instance
*/
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
/**
* Dispatch a request
*
* @param {Object} config The config specific for this request (merged with this.defaults)
*/
Axios.prototype.request = function request(config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof config === 'string') {
config = arguments[1] || {};
config.url = arguments[0];
} else {
config = config || {};
}
config = mergeConfig(this.defaults, config);
// Set config.method
if (config.method) {
config.method = config.method.toLowerCase();
} else if (this.defaults.method) {
config.method = this.defaults.method.toLowerCase();
} else {
config.method = 'get';
}
// Hook up interceptors middleware
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
Axios.prototype.getUri = function getUri(config) {
config = mergeConfig(this.defaults, config);
return buildURL(config.url, config.params, config.paramsSerializer).replace(/^\?/, '');
};
// Provide aliases for supported request methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url,
data: data
}));
};
});
module.exports = Axios;
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
function encode(val) {
return encodeURIComponent(val).
replace(/%40/gi, '@').
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%20/g, '+').
replace(/%5B/gi, '[').
replace(/%5D/gi, ']');
}
/**
* Build a URL by appending params to the end
*
* @param {string} url The base of the url (e.g., http://www.google.com)
* @param {object} [params] The params to be appended
* @returns {string} The formatted url
*/
module.exports = function buildURL(url, params, paramsSerializer) {
/*eslint no-param-reassign:0*/
if (!params) {
return url;
}
var serializedParams;
if (paramsSerializer) {
serializedParams = paramsSerializer(params);
} else if (utils.isURLSearchParams(params)) {
serializedParams = params.toString();
} else {
var parts = [];
utils.forEach(params, function serialize(val, key) {
if (val === null || typeof val === 'undefined') {
return;
}
if (utils.isArray(val)) {
key = key + '[]';
} else {
val = [val];
}
utils.forEach(val, function parseValue(v) {
if (utils.isDate(v)) {
v = v.toISOString();
} else if (utils.isObject(v)) {
v = JSON.stringify(v);
}
parts.push(encode(key) + '=' + encode(v));
});
});
serializedParams = parts.join('&');
}
if (serializedParams) {
var hashmarkIndex = url.indexOf('#');
if (hashmarkIndex !== -1) {
url = url.slice(0, hashmarkIndex);
}
url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
}
return url;
};
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
function InterceptorManager() {
this.handlers = [];
}
/**
* Add a new interceptor to the stack
*
* @param {Function} fulfilled The function to handle `then` for a `Promise`
* @param {Function} rejected The function to handle `reject` for a `Promise`
*
* @return {Number} An ID used to remove interceptor later
*/
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
/**
* Remove an interceptor from the stack
*
* @param {Number} id The ID that was returned by `use`
*/
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
};
/**
* Iterate over all the registered interceptors
*
* This method is particularly useful for skipping over any
* interceptors that may have become `null` calling `eject`.
*
* @param {Function} fn The function to call for each interceptor
*/
InterceptorManager.prototype.forEach = function forEach(fn) {
utils.forEach(this.handlers, function forEachHandler(h) {
if (h !== null) {
fn(h);
}
});
};
module.exports = InterceptorManager;
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
var transformData = __webpack_require__(8);
var isCancel = __webpack_require__(9);
var defaults = __webpack_require__(10);
/**
* Throws a `Cancel` if cancellation has been requested.
*/
function throwIfCancellationRequested(config) {
if (config.cancelToken) {
config.cancelToken.throwIfRequested();
}
}
/**
* Dispatch a request to the server using the configured adapter.
*
* @param {object} config The config that is to be used for the request
* @returns {Promise} The Promise to be fulfilled
*/
module.exports = function dispatchRequest(config) {
throwIfCancellationRequested(config);
// Ensure headers exist
config.headers = config.headers || {};
// Transform request data
config.data = transformData(
config.data,
config.headers,
config.transformRequest
);
// Flatten headers
config.headers = utils.merge(
config.headers.common || {},
config.headers[config.method] || {},
config.headers
);
utils.forEach(
['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
function cleanHeaderConfig(method) {
delete config.headers[method];
}
);
var adapter = config.adapter || defaults.adapter;
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Transform response data
response.data = transformData(
response.data,
response.headers,
config.transformResponse
);
return response;
}, function onAdapterRejection(reason) {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
// Transform response data
if (reason && reason.response) {
reason.response.data = transformData(
reason.response.data,
reason.response.headers,
config.transformResponse
);
}
}
return Promise.reject(reason);
});
};
/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
/**
* Transform the data for a request or a response
*
* @param {Object|String} data The data to be transformed
* @param {Array} headers The headers for the request or response
* @param {Array|Function} fns A single function or Array of functions
* @returns {*} The resulting transformed data
*/
module.exports = function transformData(data, headers, fns) {
/*eslint no-param-reassign:0*/
utils.forEach(fns, function transform(fn) {
data = fn(data, headers);
});
return data;
};
/***/ }),
/* 9 */
/***/ (function(module, exports) {
'use strict';
module.exports = function isCancel(value) {
return !!(value && value.__CANCEL__);
};
/***/ }),
/* 10 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
var normalizeHeaderName = __webpack_require__(11);
var DEFAULT_CONTENT_TYPE = {
'Content-Type': 'application/x-www-form-urlencoded'
};
function setContentTypeIfUnset(headers, value) {
if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
headers['Content-Type'] = value;
}
}
function getDefaultAdapter() {
var adapter;
if (typeof XMLHttpRequest !== 'undefined') {
// For browsers use XHR adapter
adapter = __webpack_require__(12);
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = __webpack_require__(12);
}
return adapter;
}
var defaults = {
adapter: getDefaultAdapter(),
transformRequest: [function transformRequest(data, headers) {
normalizeHeaderName(headers, 'Accept');
normalizeHeaderName(headers, 'Content-Type');
if (utils.isFormData(data) ||
utils.isArrayBuffer(data) ||
utils.isBuffer(data) ||
utils.isStream(data) ||
utils.isFile(data) ||
utils.isBlob(data)
) {
return data;
}
if (utils.isArrayBufferView(data)) {
return data.buffer;
}
if (utils.isURLSearchParams(data)) {
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
return data.toString();
}
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}
return data;
}],
transformResponse: [function transformResponse(data) {
/*eslint no-param-reassign:0*/
if (typeof data === 'string') {
try {
data = JSON.parse(data);
} catch (e) { /* Ignore */ }
}
return data;
}],
/**
* A timeout in milliseconds to abort a request. If set to 0 (default) a
* timeout is not created.
*/
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: function validateStatus(status) {
return status >= 200 && status < 300;
}
};
defaults.headers = {
common: {
'Accept': 'application/json, text/plain, */*'
}
};
utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {
defaults.headers[method] = {};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});
module.exports = defaults;
/***/ }),
/* 11 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
module.exports = function normalizeHeaderName(headers, normalizedName) {
utils.forEach(headers, function processHeader(value, name) {
if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
headers[normalizedName] = value;
delete headers[name];
}
});
};
/***/ }),
/* 12 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
var settle = __webpack_require__(13);
var buildURL = __webpack_require__(5);
var buildFullPath = __webpack_require__(16);
var parseHeaders = __webpack_require__(19);
var isURLSameOrigin = __webpack_require__(20);
var createError = __webpack_require__(14);
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var requestData = config.data;
var requestHeaders = config.headers;
if (utils.isFormData(requestData)) {
delete requestHeaders['Content-Type']; // Let the browser set it
}
var request = new XMLHttpRequest();
// HTTP basic authentication
if (config.auth) {
var username = config.auth.username || '';
var password = config.auth.password || '';
requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
}
var fullPath = buildFullPath(config.baseURL, config.url);
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
// Set the request timeout in MS
request.timeout = config.timeout;
// Listen for ready state
request.onreadystatechange = function handleLoad() {
if (!request || request.readyState !== 4) {
return;
}
// The request errored out and we didn't get a response, this will be
// handled by onerror instead
// With one exception: request that using file: protocol, most browsers
// will return status as 0 even though it's a successful request
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
return;
}
// Prepare the response
var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
var response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config: config,
request: request
};
settle(resolve, reject, response);
// Clean up request
request = null;
};
// Handle browser request cancellation (as opposed to a manual cancellation)
request.onabort = function handleAbort() {
if (!request) {
return;
}
reject(createError('Request aborted', config, 'ECONNABORTED', request));
// Clean up request
request = null;
};
// Handle low level network errors
request.onerror = function handleError() {
// Real errors are hidden from us by the browser
// onerror should only fire if it's a network error
reject(createError('Network Error', config, null, request));
// Clean up request
request = null;
};
// Handle timeout
request.ontimeout = function handleTimeout() {
var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded';
if (config.timeoutErrorMessage) {
timeoutErrorMessage = config.timeoutErrorMessage;
}
reject(createError(timeoutErrorMessage, config, 'ECONNABORTED',
request));
// Clean up request
request = null;
};
// Add xsrf header
// This is only done if running in a standard browser environment.
// Specifically not if we're in a web worker, or react-native.
if (utils.isStandardBrowserEnv()) {
var cookies = __webpack_require__(21);
// Add xsrf header
var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
cookies.read(config.xsrfCookieName) :
undefined;
if (xsrfValue) {
requestHeaders[config.xsrfHeaderName] = xsrfValue;
}
}
// Add headers to the request
if ('setRequestHeader' in request) {
utils.forEach(requestHeaders, function setRequestHeader(val, key) {
if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
// Remove Content-Type if data is undefined
delete requestHeaders[key];
} else {
// Otherwise add header to the request
request.setRequestHeader(key, val);
}
});
}
// Add withCredentials to request if needed
if (!utils.isUndefined(config.withCredentials)) {
request.withCredentials = !!config.withCredentials;
}
// Add responseType to request if needed
if (config.responseType) {
try {
request.responseType = config.responseType;
} catch (e) {
// Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.
// But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
if (config.responseType !== 'json') {
throw e;
}
}
}
// Handle progress if needed
if (typeof config.onDownloadProgress === 'function') {
request.addEventListener('progress', config.onDownloadProgress);
}
// Not all browsers support upload events
if (typeof config.onUploadProgress === 'function' && request.upload) {
request.upload.addEventListener('progress', config.onUploadProgress);
}
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
if (requestData === undefined) {
requestData = null;
}
// Send the request
request.send(requestData);
});
};
/***/ }),
/* 13 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var createError = __webpack_require__(14);
/**
* Resolve or reject a Promise based on response status.
*
* @param {Function} resolve A function that resolves the promise.
* @param {Function} reject A function that rejects the promise.
* @param {object} response The response.
*/
module.exports = function settle(resolve, reject, response) {
var validateStatus = response.config.validateStatus;
if (!validateStatus || validateStatus(response.status)) {
resolve(response);
} else {
reject(createError(
'Request failed with status code ' + response.status,
response.config,
null,
response.request,
response
));
}
};
/***/ }),
/* 14 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var enhanceError = __webpack_require__(15);
/**
* Create an Error with the specified message, config, error code, request and response.
*
* @param {string} message The error message.
* @param {Object} config The config.
* @param {string} [code] The error code (for example, 'ECONNABORTED').
* @param {Object} [request] The request.
* @param {Object} [response] The response.
* @returns {Error} The created error.
*/
module.exports = function createError(message, config, code, request, response) {
var error = new Error(message);
return enhanceError(error, config, code, request, response);
};
/***/ }),
/* 15 */
/***/ (function(module, exports) {
'use strict';
/**
* Update an Error with the specified config, error code, and response.
*
* @param {Error} error The error to update.
* @param {Object} config The config.
* @param {string} [code] The error code (for example, 'ECONNABORTED').
* @param {Object} [request] The request.
* @param {Object} [response] The response.
* @returns {Error} The error.
*/
module.exports = function enhanceError(error, config, code, request, response) {
error.config = config;
if (code) {
error.code = code;
}
error.request = request;
error.response = response;
error.isAxiosError = true;
error.toJSON = function() {
return {
// Standard
message: this.message,
name: this.name,
// Microsoft
description: this.description,
number: this.number,
// Mozilla
fileName: this.fileName,
lineNumber: this.lineNumber,
columnNumber: this.columnNumber,
stack: this.stack,
// Axios
config: this.config,
code: this.code
};
};
return error;
};
/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var isAbsoluteURL = __webpack_require__(17);
var combineURLs = __webpack_require__(18);
/**
* Creates a new URL by combining the baseURL with the requestedURL,
* only when the requestedURL is not already an absolute URL.
* If the requestURL is absolute, this function returns the requestedURL untouched.
*
* @param {string} baseURL The base URL
* @param {string} requestedURL Absolute or relative URL to combine
* @returns {string} The combined full path
*/
module.exports = function buildFullPath(baseURL, requestedURL) {
if (baseURL && !isAbsoluteURL(requestedURL)) {
return combineURLs(baseURL, requestedURL);
}
return requestedURL;
};
/***/ }),
/* 17 */
/***/ (function(module, exports) {
'use strict';
/**
* Determines whether the specified URL is absolute
*
* @param {string} url The URL to test
* @returns {boolean} True if the specified URL is absolute, otherwise false
*/
module.exports = function isAbsoluteURL(url) {
// A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
// RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
// by any combination of letters, digits, plus, period, or hyphen.
return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url);
};
/***/ }),
/* 18 */
/***/ (function(module, exports) {
'use strict';
/**
* Creates a new URL by combining the specified URLs
*
* @param {string} baseURL The base URL
* @param {string} relativeURL The relative URL
* @returns {string} The combined URL
*/
module.exports = function combineURLs(baseURL, relativeURL) {
return relativeURL
? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
: baseURL;
};
/***/ }),
/* 19 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
// Headers whose duplicates are ignored by node
// c.f. https://nodejs.org/api/http.html#http_message_headers
var ignoreDuplicateOf = [
'age', 'authorization', 'content-length', 'content-type', 'etag',
'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since',
'last-modified', 'location', 'max-forwards', 'proxy-authorization',
'referer', 'retry-after', 'user-agent'
];
/**
* Parse headers into an object
*
* ```
* Date: Wed, 27 Aug 2014 08:58:49 GMT
* Content-Type: application/json
* Connection: keep-alive
* Transfer-Encoding: chunked
* ```
*
* @param {String} headers Headers needing to be parsed
* @returns {Object} Headers parsed into an object
*/
module.exports = function parseHeaders(headers) {
var parsed = {};
var key;
var val;
var i;
if (!headers) { return parsed; }
utils.forEach(headers.split('\n'), function parser(line) {
i = line.indexOf(':');
key = utils.trim(line.substr(0, i)).toLowerCase();
val = utils.trim(line.substr(i + 1));
if (key) {
if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) {
return;
}
if (key === 'set-cookie') {
parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]);
} else {
parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
}
}
});
return parsed;
};
/***/ }),
/* 20 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
module.exports = (
utils.isStandardBrowserEnv() ?
// Standard browser envs have full support of the APIs needed to test
// whether the request URL is of the same origin as current location.
(function standardBrowserEnv() {
var msie = /(msie|trident)/i.test(navigator.userAgent);
var urlParsingNode = document.createElement('a');
var originURL;
/**
* Parse a URL to discover it's components
*
* @param {String} url The URL to be parsed
* @returns {Object}
*/
function resolveURL(url) {
var href = url;
if (msie) {
// IE needs attribute set twice to normalize properties
urlParsingNode.setAttribute('href', href);
href = urlParsingNode.href;
}
urlParsingNode.setAttribute('href', href);
// urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
return {
href: urlParsingNode.href,
protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
host: urlParsingNode.host,
search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
hostname: urlParsingNode.hostname,
port: urlParsingNode.port,
pathname: (urlParsingNode.pathname.charAt(0) === '/') ?
urlParsingNode.pathname :
'/' + urlParsingNode.pathname
};
}
originURL = resolveURL(window.location.href);
/**
* Determine if a URL shares the same origin as the current location
*
* @param {String} requestURL The URL to test
* @returns {boolean} True if URL shares the same origin, otherwise false
*/
return function isURLSameOrigin(requestURL) {
var parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL;
return (parsed.protocol === originURL.protocol &&
parsed.host === originURL.host);
};
})() :
// Non standard browser envs (web workers, react-native) lack needed support.
(function nonStandardBrowserEnv() {
return function isURLSameOrigin() {
return true;
};
})()
);
/***/ }),
/* 21 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
module.exports = (
utils.isStandardBrowserEnv() ?
// Standard browser envs support document.cookie
(function standardBrowserEnv() {
return {
write: function write(name, value, expires, path, domain, secure) {
var cookie = [];
cookie.push(name + '=' + encodeURIComponent(value));
if (utils.isNumber(expires)) {
cookie.push('expires=' + new Date(expires).toGMTString());
}
if (utils.isString(path)) {
cookie.push('path=' + path);
}
if (utils.isString(domain)) {
cookie.push('domain=' + domain);
}
if (secure === true) {
cookie.push('secure');
}
document.cookie = cookie.join('; ');
},
read: function read(name) {
var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
return (match ? decodeURIComponent(match[3]) : null);
},
remove: function remove(name) {
this.write(name, '', Date.now() - 86400000);
}
};
})() :
// Non standard browser env (web workers, react-native) lack needed support.
(function nonStandardBrowserEnv() {
return {
write: function write() {},
read: function read() { return null; },
remove: function remove() {}
};
})()
);
/***/ }),
/* 22 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var utils = __webpack_require__(2);
/**
* Config-specific merge-function which creates a new config-object
* by merging two configuration objects together.
*
* @param {Object} config1
* @param {Object} config2
* @returns {Object} New object resulting from merging config2 to config1
*/
module.exports = function mergeConfig(config1, config2) {
// eslint-disable-next-line no-param-reassign
config2 = config2 || {};
var config = {};
var valueFromConfig2Keys = ['url', 'method', 'params', 'data'];
var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy'];
var defaultToConfig2Keys = [
'baseURL', 'url', 'transformRequest', 'transformResponse', 'paramsSerializer',
'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress',
'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent',
'httpsAgent', 'cancelToken', 'socketPath'
];
utils.forEach(valueFromConfig2Keys, function valueFromConfig2(prop) {
if (typeof config2[prop] !== 'undefined') {
config[prop] = config2[prop];
}
});
utils.forEach(mergeDeepPropertiesKeys, function mergeDeepProperties(prop) {
if (utils.isObject(config2[prop])) {
config[prop] = utils.deepMerge(config1[prop], config2[prop]);
} else if (typeof config2[prop] !== 'undefined') {
config[prop] = config2[prop];
} else if (utils.isObject(config1[prop])) {
config[prop] = utils.deepMerge(config1[prop]);
} else if (typeof config1[prop] !== 'undefined') {
config[prop] = config1[prop];
}
});
utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) {
if (typeof config2[prop] !== 'undefined') {
config[prop] = config2[prop];
} else if (typeof config1[prop] !== 'undefined') {
config[prop] = config1[prop];
}
});
var axiosKeys = valueFromConfig2Keys
.concat(mergeDeepPropertiesKeys)
.concat(defaultToConfig2Keys);
var otherKeys = Object
.keys(config2)
.filter(function filterAxiosKeys(key) {
return axiosKeys.indexOf(key) === -1;
});
utils.forEach(otherKeys, function otherKeysDefaultToConfig2(prop) {
if (typeof config2[prop] !== 'undefined') {
config[prop] = config2[prop];
} else if (typeof config1[prop] !== 'undefined') {
config[prop] = config1[prop];
}
});
return config;
};
/***/ }),
/* 23 */
/***/ (function(module, exports) {
'use strict';
/**
* A `Cancel` is an object that is thrown when an operation is canceled.
*
* @class
* @param {string=} message The message.
*/
function Cancel(message) {
this.message = message;
}
Cancel.prototype.toString = function toString() {
return 'Cancel' + (this.message ? ': ' + this.message : '');
};
Cancel.prototype.__CANCEL__ = true;
module.exports = Cancel;
/***/ }),
/* 24 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var Cancel = __webpack_require__(23);
/**
* A `CancelToken` is an object that can be used to request cancellation of an operation.
*
* @class
* @param {Function} executor The executor function.
*/
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
var token = this;
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
}
/**
* Throws a `Cancel` if cancellation has been requested.
*/
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
if (this.reason) {
throw this.reason;
}
};
/**
* Returns an object that contains a new `CancelToken` and a function that, when called,
* cancels the `CancelToken`.
*/
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
module.exports = CancelToken;
/***/ }),
/* 25 */
/***/ (function(module, exports) {
'use strict';
/**
* Syntactic sugar for invoking a function and expanding an array for arguments.
*
* Common use case would be to use `Function.prototype.apply`.
*
* ```js
* function f(x, y, z) {}
* var args = [1, 2, 3];
* f.apply(null, args);
* ```
*
* With `spread` this example can be re-written.
*
* ```js
* spread(function(x, y, z) {})([1, 2, 3]);
* ```
*
* @param {Function} callback
* @returns {Function}
*/
module.exports = function spread(callback) {
return function wrap(arr) {
return callback.apply(null, arr);
};
};
/***/ })
/******/ ])
});
;
//# sourceMappingURL=axios.map
\ No newline at end of file
This diff could not be displayed because it is too large.
window._serverHost = window.location.hostname === 'localhost' ? 'store.keliuyun.com:9998' : window.location.host
window._baseUrl = `http://${window._serverHost}`
window._CONF_ = {
reportApiUrl: '',
apiUrl: window._baseUrl,
webSockUrl: ''
}
const log = console.log.bind(console)
/**
* [MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie#Syntax)
*/
const Cookies = {
get: function (sKey) {
return decodeURIComponent(
document.cookie.replace(
new RegExp(
"(?:(?:^|.*;)\\s*" +
encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") +
"\\s*\\=\\s*([^;]*).*$)|^.*$"
), "$1"
)
) || null
},
/**
* 写入
* @param {string} sKey necessary
* @param {string} sValue necessary
* @param {number|null|date|object|Infinity|string} vEnd optional
* @param {string|null} sPath optional
* @param {string|null} sDomain optional
* @param {boolean|null} bSecure optional
*/
set: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
if (!sKey ||
/^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)
) {
return false
}
let sExpires = ''
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires = vEnd === Infinity
? '; expires=Fri, 31 Dec 9999 23:59:59 GMT'
: '; max-age=' + vEnd
break;
case String:
sExpires = '; expires=' + vEnd
break;
case Date:
sExpires = '; expires=' + vEnd.toUTCString()
break;
}
}
document.cookie = encodeURIComponent(sKey) + '=' +
encodeURIComponent(sValue) + sExpires +
(sDomain ? '; domain=' + sDomain : '') +
(sPath ? '; path=' + sPath : '') +
(bSecure ? '; secure' : '')
return true
},
remove: function (sKey, sPath, sDomain) {
if (!sKey || !this.has(sKey)) return false
document.cookie = encodeURIComponent(sKey) +
'=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +
(sDomain ? '; domain=' + sDomain : '') +
(sPath ? '; path=' + sPath : '')
return true
},
has: function (sKey) {
return (
new RegExp('(?:^|;\\s*)' +
encodeURIComponent(sKey).replace(/[-.+*]/g, '\\$&') +
'\\s*\\='
)
).test(document.cookie)
},
keys: function () {
let aKeys = document.cookie.replace(
/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g,
''
).split(/\s*(?:\=[^;]*)?;\s*/)
for (let nIdx = 0;nIdx < aKeys.length;nIdx++) {
aKeys[nIdx] = decodeURIComponent(aKeys[nIdx])
}
return aKeys
}
}
const trafficOptions = [
"mall/countData",
"floor/countData",
"zone/countData",
"gate/countData"
]
const faceOptions = [
"mall/faceSta",
"floor/faceSta",
"zone/faceSta",
"gate/faceSta"
]
// const TAB_API = {
// featureRevisit: '',
// featureLibRebuild: [],
// }
new Vue({
el: "#app",
data: function() {
return {
currentIndex6: '1',
pickerOpts: {
disabledDate(time) {
return Date.parse(time) > Date.parse(new Date())
}
},
radio: "mall",
dateFormat: "rerun",
dateLevelList: [
{label: 'rerun', name: '数据重跑'},
{label: 'repair', name: '数据修补'},
{label: 'revisitFeature', name: '特征重提'},
{label: 'rebuildFeatureLib', name: '特征库重建'},
{label: 'rematchPerson', name: '人员重新比对'},
{label: 'snapGatherClass', name: '抓拍聚类'},
],
UrlType: "trafficRecognition",
compareType: "custom",
count: null,
dateCount: null,
day: "",
hour: "",
min: "",
startDate: "",
endDate: "",
sourceDate: "",
sourceStartTime: "00:00:00",
sourceEndTime: "23:59:59",
aimsDate: "",
aimsStartTime: "00:00:00",
aimsEndTime: "23:59:59",
referenceDate: "",
repairDate: "",
accountVal: [],
mallVal: [],
mallOpts: [],
accountId: [],
accoutOpts: [],
deviceVal: "",
gateVal: "",
channelVal: "",
showDiv: true,
loading: "",
gateOpt: [],
deviceOpt: [],
channelOpt: [],
date: "",
butShow: false,
startShow: false,
tafficShow: false,
startRange: "0.85",
endRange: "1.2",
isMallSelAll: false,
isAccoutSelAll: false,
//全选
checkedTraffic: [],
checkAllTraffic: false,
isIndeterminateTraffic: false,
checkedFace: [],
checkAllFace: false,
isIndeterminateFace: false,
checkTraffic: [
{
name: "",
value: "mall/countData"
},
{
name: "",
value: "floor/countData"
},
{
name: "",
value: "zone/countData"
},
{
name: "",
value: "gate/countData"
}
],
checkFace: [
{
name: "",
value: "mall/faceSta"
},
{
name: "",
value: "floor/faceSta"
},
{
name: "",
value: "zone/faceSta"
},
{
name: "",
value: "gate/faceSta"
}
],
progressName: {
mallcountData: "商场客流",
floorcountData: "楼层客流",
zonecountData: "店铺客流",
gatecountData: "监控点客流",
mallfaceSta: "商场人脸",
floorfaceSta: "楼层人脸",
zonefaceSta: "店铺人脸",
gatefaceSta: "监控点人脸"
},
startTime: "",
endTime: "",
traffStartTime: "00:00:00",
traffEndTime: "23:59:59",
webSocketObj: {},
repairWebSocket: null,
dateTime: [],
progressList: [],
repairProgList: [],
traProgList: [],
tipShow: false,
tipStyle: {},
lineDate: "",
lineMallId: "",
lineMallName: "",
locationHref: false,
/// 特征重提
query: {
accountVal: [],
mallVal: [],
dateVal: null
},
featureRevisitType: 0,
featureLibRebuildType: 1,
rematchPersonType: 1,
featureRevisitList: [
{label: '人脸+全身照特征', value: 0},
{label: '人脸特征', value: 1},
{label: '全身照特征', value: 2},
{label: '店员特征', value: 3}
],
featureLibRebuildList: [
{label: '店员库重建', value: 1},
{label: '顾客库重建', value: 2}
],
rematchPersonList: [
{label: '店员对比', value: 1},
{label: '顾客对比', value: 2}
],
socket: null,
results: [],
startTiming: 0,
endTiming: 0,
footerText: ''
}
},
filters: {
formatTime(val) {
function autoPrefixZero(num) {
return num > 10 ? num : '0' + num
}
const day = parseInt(val / (24 * 60 * 60 * 1000)) + 1
const hour = parseInt(val % (24 * 60 * 60 * 1000) / (60 * 60 * 1000))
const minutes = parseInt(val % (60 * 60 * 1000) / (60 * 1000))
const seconds = parseInt(val % (60 * 1000) / 1000)
if (val < 1000 || val < 60 * 1000)
{
return `${val % (60 * 1000) / 1000} 秒`
}
else if (val < 60 * 60 * 1000)
{
return `${autoPrefixZero(minutes)} 分钟 ${autoPrefixZero(seconds)} 秒`
}
else if (val < 24 * 60 * 60 * 1000)
{
return `${autoPrefixZero(hour)} 小时 ${autoPrefixZero(minutes)} 分钟 ${autoPrefixZero(seconds)} 秒`
}
else
{
return `${autoPrefixZero(day)}${autoPrefixZero(hour)} 小时 ${autoPrefixZero(minutes)} 分钟 ${autoPrefixZero(seconds)} 秒`
}
}
},
computed: {
isResultsShow() {
return this.dateFormat === 'revisitFeature' ||
this.dateFormat === 'rebuildFeatureLib' ||
this.dateFormat === 'rematchPerson'
},
isSendDateParam() {
if (
(this.dateFormat === 'rebuildFeatureLib'
&& this.featureLibRebuildType === 1
) || (
this.dateFormat === 'revisitFeature'
&& this.featureRevisitType === 3)
)
{
return false
}
return true
},
totalTime() {
const {startTiming, endTiming} = this
return endTiming - startTiming
// return this.formatDateToStamp(endTiming) - this.formatDateToStamp(startTiming)
}
},
watch: {
accountVal: {
handler: function(val) {
if (val && val.length)
{
this.query.accountVal = val
}
},
deep: true
},
mallVal: {
handler: function(val) {
if (val && val.length)
{
this.query.mallVal = val
}
},
deep: true
},
dateFormat: function(val) {
var typeHandler = {
'revisitFeature': this.featureRevisitType,
'rebuildFeatureLib': this.featureLibRebuildType,
'rematchPerson': this.rematchPersonType
}
this.footerText = val === 'compare' ? '数据对比' : this.dateLevelList.find(item => item.label === val).name
this.socket && this.socket.close()
this.results.length && (this.results = [])
this.startTiming = this.endTiming = 0
this.query.type = typeof typeHandler[val] === 'undefined'
? null
: typeHandler[val]
},
featureRevisitType(val) {
this.query.type = val
},
featureLibRebuildType(val) {
this.query.type = val
},
rematchPersonType(val) {
this.query.type = val
}
},
created: function() {
this.locationHref =
location.href.indexOf("?super") != -1 ? true : false
this.getAccount()
},
mounted: function() {
this.query.dateVal = this.createDate()
this.startTime = this.createDate()
this.endTime = this.createDate()
},
methods: {
createDate() {
var nowDate = new Date()
var day = nowDate.getDate()
var month = nowDate.getMonth() + 1
var year = nowDate.getFullYear()
if (month >= 1 && month <= 9)
{
month = "0" + month
}
if (day >= 0 && day <= 9)
{
day = "0" + day
}
return year + "-" + month + "-" + day
},
getProgressName(val) {
return this.progressName[val]
},
getProgressStyle(stepCount, status, oldStepCount) {
if (stepCount == "stepType")
{
if (status == "gatecountData" || status == "gatefaceSta")
{
return {"margin-left": "448px", "font-size": "18px"}
}
else
{
return {"margin-left": "465px", "font-size": "18px"}
}
}
else
{
return {
width: (stepCount - oldStepCount) * 405 + "px",
"background-color": status ? "#409EFF" : "#f56c6c",
"margin-left": oldStepCount * 405 + 50 + "px"
}
}
},
lineOver(tag, dates, mallIds, mallNames) {
let evt = tag || window.event,
_top,
_left
_top = window.innerHeight - evt.y
_left = window.innerWidth - evt.x
this.tipStyle = {
top: evt.y - 50 + "px",
left: evt.x + "px"
}
this.lineDate = dates
this.lineMallId = mallIds.join(",")
this.lineMallName = mallNames
this.tipShow = true
},
lineOut() {
this.tipShow = false
},
handleCheckAllChangeTraffic(val) {
// console.log('val',val)
this.checkedTraffic = val ? trafficOptions : []
// console.log(this.checkedTraffic)
this.isIndeterminateTraffic = false
},
handleCheckAllChangeFace(val) {
// console.log('val',val)
this.checkedFace = val ? faceOptions : []
// console.log(this.checkedFace)
this.isIndeterminateFace = false
},
handleCheckedCitiesChangeTraffic(value) {
// console.log(this.checkedTraffic)
let checkedCount = value.length
this.checkAllTraffic = checkedCount === this.checkTraffic.length
this.isIndeterminateTraffic =
checkedCount > 0 && checkedCount < this.checkTraffic.length
},
handleCheckedCitiesChangeFace(value) {
// console.log(this.checkedFace)
let checkedCount = value.length
this.checkAllFace = checkedCount === this.checkFace.length
this.isIndeterminateFace =
checkedCount > 0 && checkedCount < this.checkFace.length
},
accountchange(linkGate) {
this.isAccoutSelAll = this.isAccoutSelAll
? this.accountVal.length < this.accoutOpts.length
? false
: true
: this.accountVal.length < this.accoutOpts.length
? false
: true
if (this.accountVal.length > 0)
{
this.getMall(linkGate)
}
},
mallchange(linkGate) {
this.isMallSelAll = this.isMallSelAll
? this.mallVal.length < this.mallOpts.length
? false
: true
: this.mallVal.length < this.mallOpts.length
? false
: true
if (linkGate)
{
this.getGate()
}
},
selAllHandle(level) {
if (level == "accout")
{
if (this.isAccoutSelAll)
{
this.accountVal = []
this.isAccoutSelAll = false
this.getMall()
}
else
{
this.accountVal = []
this.accoutOpts.forEach(item => {
this.accountVal.push(item.id)
})
this.isAccoutSelAll = true
this.getMall()
}
}
else
{
if (this.isMallSelAll)
{
this.mallVal = []
this.isMallSelAll = false
}
else
{
this.mallVal = []
this.mallOpts.forEach(item => {
this.mallVal.push(item.id)
})
this.isMallSelAll = true
}
}
},
getAccount: function() {
var _this = this
_this.accoutOpts = []
log(454, window._CONF_.apiUrl + API.Accounts)
get(window._CONF_.apiUrl + API.Accounts).then(function(data) {
_this.accoutOpts = data
if (_this.accoutOpts.length > 0)
{
_this.accountVal = [_this.accoutOpts[0].id]
}
_this.getMall()
}).catch(err => {
console.log('err', err)
})
},
getMall: function() {
var _this = this
_this.mallOpts = []
get(window._CONF_.apiUrl + API.Malls, {
accountIds: _this.accountVal.join(",")
}).then(function(data) {
_this.mallOpts = data
if (_this.mallOpts.length > 0)
{
_this.mallVal = [_this.mallOpts[0].id]
}
_this.isMallSelAll =
_this.mallVal.length == _this.mallOpts.length ? true : false
})
},
getGate: function() {
var _this = this
get(window._CONF_.apiUrl + API.Gates, {
accountIds: _this.accountVal.join(","),
mallIds: _this.mallVal.join(',')
}).then(function(data) {
_this.gateOpt = data
_this.gateVal = _this.gateOpt[0].id
// _this.getDevice()
_this.getChannel()
})
},
getDevice: function() {
var _this = this
get(window._CONF_.apiUrl + API.Devices, {
// accountIds: _this.accountVal.join(","),
// mallIds: _this.mallVal.join(','),
gateId: this.gateVal
}).then(function(data) {
_this.deviceOpt = []
_this.deviceVal = ""
for (var i = 0; i < data.length; i++)
{
var temp = {}
temp.name = data[i]
temp.value = data[i]
temp.id = i
_this.deviceOpt.push(temp)
}
_this.deviceVal = _this.deviceOpt[0].value
})
},
//////////////////////////////////////////////////////
dateLevel: function() {
if (this.dateFormat == "repair")
{
this.getGate()
}
else if (this.dateFormat == "snapGatherClass")
{
// get(window._CONF_.apiUrl + '/face/faceRecord', {}).then(
// function(r) {
// log(r)
// }
// )
}
else
{
// this.getMall();
}
},
onMenuSelect: function(v) {
this.currentIndex6 = v
},
//////////////////////////////////////////////////////
getLevel: function() {
},
getNumber() {
this.repairProgList = []
if (this.UrlType == "trafficRecognition")
{
// this.getChannel()
}
else
{
// this.getChannel()
// this.getDevice()
}
},
getChannel() {
var _this = this
get(window._CONF_.apiUrl + API.Channels, {
// accountIds: _this.accountVal.join(","),
// mallIds: _this.mallVal.join(','),
gateId: this.gateVal
}).then(function(data) {
_this.channelOpt = []
for (var i = 0; i < data.length; i++)
{
var temp = {}
temp.name = data[i]
temp.value = data[i]
temp.id = i
_this.channelOpt.push(temp)
}
_this.channelVal =
_this.channelOpt.length > 0 ? _this.channelOpt[0].value : ""
})
},
clearDiv() {
$("#showDiv").empty()
},
startData: function() {
this.progressList = []
if (this.webSocketObj)
{
for (var key in this.webSocketObj)
{
this.webSocketObj[key].close()
}
}
let params = {},
startDate = "",
endDate = ""
params = {
startDate: this.startTime + " 00:00:00",
endDate: this.endTime + " 00:00:00",
mallIds: this.mallVal,
scheduleType: "",
mark: Date.parse(new Date())
}
this.checkedTraffic.forEach((item, index) => {
let _scheduleType = ""
let websocket = item.split("/")
websocket.forEach(item1 => {
_scheduleType += item1
})
params.scheduleType = _scheduleType
this.openWebSock(_scheduleType, item, params)
})
this.checkedFace.forEach((item, index) => {
let _scheduleType = ""
let websocket = item.split("/")
websocket.forEach(item1 => {
_scheduleType += item1
})
params.scheduleType = _scheduleType
this.openWebSock(_scheduleType, item, params)
})
},
openWebSock(wsUrl, url, params, processKey = 'progressList') {
// browser 兼容
// var wsHost = window.location.host;
var socketUrl = ""
var webSock_Url = window._CONF_.webSockUrl || window.location.host
var obj = {
stepList: []
}
obj.stepType = wsUrl
obj.mark = params.mark
if (!webSockUrl)
{
webSock = window.location.host
}
socketUrl = "ws://" + webSock_Url + WSAPI.WSAPI + wsUrl
this[processKey].push(obj)
var _this = this
if ("WebSocket" in window)
{
_this.webSocketObj[wsUrl] = new WebSocket(socketUrl)
}
else if ("MozWebSocket" in window)
{
_this.webSocketObj[wsUrl] = new MozWebSocket(socketUrl)
}
else
{
_this.webSocketObj[wsUrl] = new SockJS(socketUrl)
}
var param = JSON.parse(JSON.stringify(params))
try
{
_this.webSocketObj[wsUrl].onopen = function(event) {
console.log("WebSocket:已连接")
_this.returnData(url, param)
}
_this.webSocketObj[wsUrl].onclosed = function() {
console.log("WebSocket关闭")
}
_this.webSocketObj[wsUrl].onmessage = function(evt) {
var msg = JSON.parse(evt.data)
_this[processKey].forEach((item, index) => {
if (
item.stepType == msg.scheduleType &&
item.mark == msg.mark
)
{
var stepObj = {}
stepObj.dates = msg.dates
stepObj.mallIds = msg.mallIds
stepObj.mallNames = msg.mallNames
stepObj.status = msg.status
stepObj.stepCount = msg.stepCount
item.stepList.push(stepObj)
item.precentsucess = msg.stepCount
? Math.floor(msg.stepCount * 100)
: 0
}
})
// console.log('list',_this[processKey])
}
_this.webSocketObj[wsUrl].onerror = function(event) {
console.log("设备WebSocket:发生错误 ")
console.log(event)
}
}
catch (error)
{
}
},
returnData: function(urls, params) {
// console.log(urls,params)
var _this = this
post(window._CONF_.apiUrl + urls, JSON.stringify(params)).then(function(data) {
if (data)
{
_this.loading = ""
_this.showDiv = true
_this.renderResultToHtml(data)
}
}).catch(function(err) {
_this.loading = ""
alert("Sorry, The requested property could not be found.")
})
},
getDateCount: function() {
var _this = this
this.butShow = true
var params = {
startTime: this.sourceDate + " " + this.sourceStartTime,
endTime: this.sourceDate + " " + this.sourceEndTime,
channelSerialnum: this.channelVal
}
get(window._CONF_.apiUrl + API.FaceRecognitionsCount, params).then(function(data) {
_this.butShow = false
_this.dateCount = data
}).catch(function(err) {
_this.butShow = false
console.log(err)
})
// $.ajax({
// type: "get",
// dataType: "json",
// async: true,
// url: window._CONF_.apiUrl + urls,
// headers: {
// Authorization: Cookies.get('atoken')
// },
// data: params,
// success: function(data) {
// _this.butShow = false;
// _this.dateCount = data;
// },
// error: function(res) {
// _this.butShow = false;
// console.log(res);
// }
// });
},
repairParams: function(type) {
this.repairProgList = []
if (this.repairWebSocket)
{
this.repairWebSocket.close()
}
var url = "",
params = {}
if (type == "face")
{
this.startShow = true
setTimeout(() => {
this.startShow = false
}, 3000)
var url = API.SimulationFaceRecognition
var params = {
sourceStartDate: this.sourceDate + " " + this.sourceStartTime,
sourceEndDate: this.sourceDate + " " + this.sourceEndTime,
targetStartDate: this.aimsDate + " " + this.aimsStartTime,
targetEndDate: this.aimsDate + " " + this.aimsEndTime,
channelSerialnum: this.channelVal,
count: Number(this.count),
scheduleType: "simulationfaceRecognition",
mark: Date.parse(new Date())
}
}
else
{
this.tafficShow = true
setTimeout(() => {
this.tafficShow = false
}, 3000)
url = API.SimulationCountData
params = {
sourceStartDate: this.referenceDate + " " + this.traffStartTime,
sourceEndDate: this.referenceDate + " " + this.traffEndTime,
targetStartDate: this.repairDate + " " + this.traffStartTime,
targetEndDate: this.repairDate + " " + this.traffEndTime,
channelSerialnum: this.channelVal,
minFactor: this.startRange,
maxFactor: this.endRange,
scheduleType: "simulationcountData",
mark: Date.parse(new Date())
}
}
this.openFaceTraffWebSock(url, params)
},
compareParams: function(type) {
params = {
startDate: this.startTime + " 00:00:00",
endDate: this.endTime + " 00:00:00",
mallIds: this.mallVal,
scheduleType: "",
mark: Date.parse(new Date())
}
var url = API.Mall + this.compareType
this.returnData(url, params)
},
openFaceTraffWebSock(url, params) {
// browser 兼容
// var wsHost = window.location.host;
var socketUrl = ""
var webSock_Url = window._CONF_.webSockUrl || window.location.host
var obj = {
stepList: []
}
obj.stepType = params.scheduleType
obj.mark = params.mark
socketUrl =
"ws://" + webSock_Url + WSAPI.RecalSchedule + params.scheduleType
this.repairProgList.push(obj)
var _this = this
if ("WebSocket" in window)
{
_this.repairWebSocket = new WebSocket(socketUrl)
}
else if ("MozWebSocket" in window)
{
_this.repairWebSocket = new MozWebSocket(socketUrl)
}
else
{
_this.repairWebSocket = new SockJS(socketUrl)
}
var param = JSON.parse(JSON.stringify(params))
try
{
_this.repairWebSocket.onopen = function(event) {
console.log("WebSocket:已连接")
_this.repairData(url, params)
}
_this.repairWebSocket.onclosed = function() {
console.log("WebSocket关闭")
}
_this.repairWebSocket.onmessage = function(evt) {
var msg = JSON.parse(evt.data)
_this.repairProgList.forEach((item, index) => {
if (
item.stepType == msg.scheduleType &&
item.mark == msg.mark
)
{
var stepObj = {}
stepObj.counttime = msg.counttime
stepObj.serialnum = msg.serialnum
stepObj.status = msg.status
stepObj.stepCount = msg.stepCount
item.stepList.push(stepObj)
item.precentsucess = msg.stepCount
? Math.floor(msg.stepCount * 100)
: 0
}
})
}
_this.webSocketObj[wsUrl].onerror = function(event) {
console.log("设备WebSocket:发生错误 ")
console.log(event)
}
}
catch (error)
{
}
},
repairData(url, params) {
let that = this
post(window._CONF_.apiUrl + url, JSON.stringify(params)).then(function(data) {
if (data)
{
that.renderResultToHtml(data)
}
})
},
repairPreview: function() {
var params = {
sourceStartDate: this.referenceDate + " " + this.traffStartTime,
sourceEndDate: this.referenceDate + " " + this.traffEndTime,
targetStartDate: this.repairDate + " " + this.traffStartTime,
targetEndDate: this.repairDate + " " + this.traffEndTime,
channelSerialnum: this.channelVal,
minFactor: this.startRange,
maxFactor: this.endRange,
scheduleType: "simulationcountData",
mark: Date.parse(new Date())
}
let that = this
post(window._CONF_.apiUrl + API.PreviewCountData, JSON.stringify(params)).then(function(data) {
if (data)
{
that.renderResultToHtml(data, true)
}
})
},
renderResultToHtml(data, hasSccessDetail) {
let text = "本次共执行job " +
data.total +
" 个,成功 " +
data.success +
" 个,失败 " +
data.failed +
" 个.</br>"
if (data.failedJob && data.failedJob.length > 0)
{
text += "-----失败job详情-----</br>"
text += data.failedJob.join("</br>")
if (data.data)
{
text += "</br>" + data.data
}
}
if (data.successJob && data.successJob.length > 0)
{
text += "-----成功job详情-----</br>"
text += data.successJob.join("</br>")
if (hasSccessDetail)
{
if (data.data)
{
console.log(data.data)
data.data.forEach(item => {
text +=
"</br>" +
" 设备序列号: " +
item.deviceSerialnum +
" 时间: " +
item.counttime +
" 进客流: " +
item.innum +
" 出客流: " +
item.outnum
})
}
}
}
text += "</br>-----------------------------------------------"
text += "</br>"
text += "</br>"
text += "</br>"
$("#showDiv").append(text)
},
onSearchClick: function() {
/////////////////////////////特征重提////////////////////////////////////////////////
// '/mall/feature'
// startDate,endDate,mallIds,scheduleType,featureType
// featureType==0 提取人体+人脸;featureType==1 提取人脸特征;featureType==2提取人体特征
/////////////////////////////特征库重建////////////////////////////////////////////////
// 重新建立顾客池 /mall/customPool
// 参数 mallIds,startDate,endDate,scheduleType
// 重建建立店员特征池 /mall/staffPool
// 参数 mallIds,scheduleType
/////////////////////////////人员重新对比////////////////////////////////////////////////
// 重新匹配顾客 /mall/custom
// 参数 mallIds,startDate,endDate,scheduleType
// 店员重新比对 /mall/staff
// 参数 mallIds,startDate,endDate,scheduleType
if (this.socket)
{
this.socket.close()
this.socket = null
}
this.results = []
this.startTiming = 0
this.endTiming = 0
const TAB_API = {
revisitFeature: (val) => {
return val === 3 ? API.mallStaffFeature : API.MallFeature
},
rebuildFeatureLib: (val) => {
return val === 1 ? API.MallStaffPool : API.MallCustomPool
},
rematchPerson: (val) => {
return val === 1 ? API.MallStaff : API.MallCustom
}
}
const {dateFormat, query, isSendDateParam} = this
const {
dateVal, mallVal, type
} = query
var urlPath = TAB_API[dateFormat](type)
var scheduleType = dateFormat + type
var parameter = {
// startDate: dateVal ? dateVal + ' 00:00:00' : null,
// endDate: dateVal ? dateVal + ' 23:59:59' : null,
mallIds: mallVal || null,
scheduleType: scheduleType,
// featureType: dateFormat === 'revisitFeature' ? type : null
}
if (isSendDateParam)
{
parameter.startDate = dateVal + ' 00:00:00'
parameter.endDate = dateVal + ' 23:59:59'
}
if (dateFormat === 'revisitFeature')
{
parameter.featureType = type
}
var socketParameter = {
scheduleType: scheduleType,
// callback: 'fetchApi',
callbackUrlPath: urlPath,
callbackParam: parameter
}
this.onSocketConnect(socketParameter)
},
/**
* websocket 连接
* @param {string} scheduleType
* @param {string} wsUrl
* @param {string} callbackUrlPath
* @param {object} callbackParam
*/
onSocketConnect({scheduleType, callbackUrlPath, callbackParam}) {
var self = this,
wsUrl = window._CONF_.webSockUrl || window.location.host,
socketUrl = "ws://" + wsUrl + WSAPI.RecalSchedule + scheduleType
if ("WebSocket" in window)
{
self.socket = new WebSocket(socketUrl)
}
else if ("MozWebSocket" in window)
{
self.socket = new MozWebSocket(socketUrl)
}
else
{
self.socket = new SockJS(socketUrl)
}
try
{
self.socket.onopen = function(ev) {
self.startTiming = +new Date()
self.fetchApi(callbackUrlPath, callbackParam)
}
self.socket.onclosed = function() {
console.log('socket:onclose')
}
self.socket.onmessage = function(ev) {
var msg = JSON.parse(ev.data)
console.log('[onmessage]:', msg)
self.dealMessage(msg)
if (msg.stepCount === 1)
{
self.endTiming = +new Date()
self.socket.close()
}
}
self.socket.onerror = function(ev) {
console.log("设备WebSocket:发生错误 ")
console.log(ev)
}
}
catch (error)
{
console.log('onSocketConnect:', error)
}
},
fetchApi(urlPath, parameter) {
const {
dateVal, mallVal, type
} = this.query
var self = this
post(window._CONF_.apiUrl + urlPath, JSON.stringify(parameter)).then(function(res) {
console.log(res)
})
},
dealMessage(msg) {
// scheduleType
const {dates, mallIds, mallNames, status, stepCount, scheduleType, counter} = msg
var self = this
var resObj = {}
resObj.dates = dates
resObj.mallIds = mallIds
resObj.mallNames = mallNames
resObj.status = status
resObj.progress = self.floatToPercent(stepCount)
resObj.totalNum = 0
resObj.totalPage = 0
resObj.current = 0
resObj.curPageSize = 0
resObj.currentPage = 0
resObj.scheduleType = scheduleType
if (counter)
{
// dataNum dateMallNum step totalData totalDate totalMall totalMallDateProduct allDataCount
resObj.totalNum = counter.allDataCount
resObj.totalPage = counter.totalMallDateProduct
resObj.current = counter.dataNum
resObj.curPageSize = counter.totalData
resObj.currentPage = counter.dateMallNum
}
if (self.results.length)
{
const isSameScheduleType = self.results.some(item => item.scheduleType === scheduleType)
isSameScheduleType
? self.results.forEach(item => {
//
item.progress = self.floatToPercent(stepCount)
if (counter)
{
item.totalNum = counter.allDataCount
item.totalPage = counter.totalMallDateProduct
item.current = counter.dataNum
item.curPageSize = counter.totalData
item.currentPage = counter.dateMallNum
}
})
: self.results.push(resObj)
resObj = {}
}
else
{
self.results.push(resObj)
resObj = {}
}
// 滚动至底部
// this.$nextTick(() => {
// this.$refs.scrollbarRef.wrap.scrollTop = this.$refs.scrollbarRef.wrap.scrollHeight
// })
},
formatDateToStamp(date) {
if (!date)
{
return false
}
typeof date === 'string' && (date = new Date(date.replace(/-/g, '/')))
return date.getTime()
},
floatToPercent(floatNum) {
if (!floatNum)
{
return 0
}
var formatNum = Math.floor(floatNum * 100)
return formatNum >= 100 ? 100 : formatNum
},
onClearClick() {
if (this.dateFormat === 'revisitFeature' ||
this.dateFormat === 'rebuildFeatureLib' ||
this.dateFormat === 'rematchPerson')
{
this.startTiming = 0
this.endTiming = 0
this.results = []
}
// else {
document.getElementById('showDiv').innerHTML = ''
// }
}
}
})
This diff could not be displayed because it is too large.
/*! jQuery v3.1.0 | (c) jQuery Foundation | jquery.org/license */
!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.1.0",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null!=a?a<0?this[a+this.length]:this[a]:f.call(this)},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=r.isArray(d)))?(e?(e=!1,f=c&&r.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"label"in b&&b.disabled===a||"form"in b&&b.disabled===a||"form"in b&&b.disabled===!1&&(b.isDisabled===a||b.isDisabled!==!a&&("label"in b||!ea(b))!==a)}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e)}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(_,aa),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=V.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(_,aa),$.test(j[0].type)&&qa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&sa(j),!a)return G.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||$.test(a)&&qa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext,B=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,C=/^.[^:#\[\.,]*$/;function D(a,b,c){if(r.isFunction(b))return r.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return r.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(C.test(b))return r.filter(b,a,c);b=r.filter(b,a)}return r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType})}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(D(this,a||[],!1))},not:function(a){return this.pushStack(D(this,a||[],!0))},is:function(a){return!!D(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var E,F=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,G=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||E,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:F.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),B.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};G.prototype=r.fn,E=r(d);var H=/^(?:parents|prev(?:Until|All))/,I={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function J(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return J(a,"nextSibling")},prev:function(a){return J(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return a.contentDocument||r.merge([],a.childNodes)}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(I[a]||r.uniqueSort(e),H.test(a)&&e.reverse()),this.pushStack(e)}});var K=/\S+/g;function L(a){var b={};return r.each(a.match(K)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?L(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function M(a){return a}function N(a){throw a}function O(a,b,c){var d;try{a&&r.isFunction(d=a.promise)?d.call(a).done(b).fail(c):a&&r.isFunction(d=a.then)?d.call(a,b,c):b.call(void 0,a)}catch(a){c.call(void 0,a)}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,M,e),g(f,c,N,e)):(f++,j.call(a,g(f,c,M,e),g(f,c,N,e),g(f,c,M,c.notifyWith))):(d!==M&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==N&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:M,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:M)),c[2][3].add(g(0,a,r.isFunction(d)?d:N))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(O(a,g.done(h(c)).resolve,g.reject),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)O(e[c],h(c),g.reject);return g.promise()}});var P=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&P.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var Q=r.Deferred();r.fn.ready=function(a){return Q.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,holdReady:function(a){a?r.readyWait++:r.ready(!0)},ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||Q.resolveWith(d,[r]))}}),r.ready.then=Q.then;function R(){d.removeEventListener("DOMContentLoaded",R),a.removeEventListener("load",R),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",R),a.addEventListener("load",R));var S=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)S(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,
r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},T=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function U(){this.expando=r.expando+U.uid++}U.uid=1,U.prototype={cache:function(a){var b=a[this.expando];return b||(b={},T(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){r.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(K)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var V=new U,W=new U,X=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Y=/[A-Z]/g;function Z(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Y,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c||"false"!==c&&("null"===c?null:+c+""===c?+c:X.test(c)?JSON.parse(c):c)}catch(e){}W.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return W.hasData(a)||V.hasData(a)},data:function(a,b,c){return W.access(a,b,c)},removeData:function(a,b){W.remove(a,b)},_data:function(a,b,c){return V.access(a,b,c)},_removeData:function(a,b){V.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=W.get(f),1===f.nodeType&&!V.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),Z(f,d,e[d])));V.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){W.set(this,a)}):S(this,function(b){var c;if(f&&void 0===b){if(c=W.get(f,a),void 0!==c)return c;if(c=Z(f,a),void 0!==c)return c}else this.each(function(){W.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){W.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=V.get(a,b),c&&(!d||r.isArray(c)?d=V.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return V.get(a,c)||V.access(a,c,{empty:r.Callbacks("once memory").add(function(){V.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=V.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var $=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,_=new RegExp("^(?:([+-])=|)("+$+")([a-z%]*)$","i"),aa=["Top","Right","Bottom","Left"],ba=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ca=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function da(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&_.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ea={};function fa(a){var b,c=a.ownerDocument,d=a.nodeName,e=ea[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ea[d]=e,e)}function ga(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=V.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&ba(d)&&(e[f]=fa(d))):"none"!==c&&(e[f]="none",V.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ga(this,!0)},hide:function(){return ga(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){ba(this)?r(this).show():r(this).hide()})}});var ha=/^(?:checkbox|radio)$/i,ia=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,ja=/^$|\/(?:java|ecma)script/i,ka={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ka.optgroup=ka.option,ka.tbody=ka.tfoot=ka.colgroup=ka.caption=ka.thead,ka.th=ka.td;function la(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&r.nodeName(a,b)?r.merge([a],c):c}function ma(a,b){for(var c=0,d=a.length;c<d;c++)V.set(a[c],"globalEval",!b||V.get(b[c],"globalEval"))}var na=/<|&#?\w+;/;function oa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(na.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ia.exec(f)||["",""])[1].toLowerCase(),i=ka[h]||ka._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=la(l.appendChild(f),"script"),j&&ma(g),c){k=0;while(f=g[k++])ja.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var pa=d.documentElement,qa=/^key/,ra=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,sa=/^([^.]*)(?:\.(.+)|)/;function ta(){return!0}function ua(){return!1}function va(){try{return d.activeElement}catch(a){}}function wa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)wa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ua;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(pa,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(K)||[""],j=b.length;while(j--)h=sa.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.hasData(a)&&V.get(a);if(q&&(i=q.events)){b=(b||"").match(K)||[""],j=b.length;while(j--)if(h=sa.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&V.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(V.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;c<h;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?r(e,this).index(i)>-1:r.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==va()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===va()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&r.nodeName(this,"input"))return this.click(),!1},_default:function(a){return r.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ta:ua,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:ua,isPropagationStopped:ua,isImmediatePropagationStopped:ua,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ta,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ta,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ta,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&qa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ra.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return wa(this,a,b,c,d)},one:function(a,b,c,d){return wa(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=ua),this.each(function(){r.event.remove(this,a,c,b)})}});var xa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,ya=/<script|<style|<link/i,za=/checked\s*(?:[^=]|=\s*.checked.)/i,Aa=/^true\/(.*)/,Ba=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ca(a,b){return r.nodeName(a,"table")&&r.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a:a}function Da(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ea(a){var b=Aa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(V.hasData(a)&&(f=V.access(a),g=V.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}W.hasData(a)&&(h=W.access(a),i=r.extend({},h),W.set(b,i))}}function Ga(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ha.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ha(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&za.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(m&&(e=oa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(la(e,"script"),Da),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,la(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ea),l=0;l<i;l++)j=h[l],ja.test(j.type||"")&&!V.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Ba,""),k))}return a}function Ia(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(la(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&ma(la(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(xa,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=la(h),f=la(a),d=0,e=f.length;d<e;d++)Ga(f[d],g[d]);if(b)if(c)for(f=f||la(a),g=g||la(h),d=0,e=f.length;d<e;d++)Fa(f[d],g[d]);else Fa(a,h);return g=la(h,"script"),g.length>0&&ma(g,!i&&la(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(T(c)){if(b=c[V.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[V.expando]=void 0}c[W.expando]&&(c[W.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return S(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(la(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return S(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!ya.test(a)&&!ka[(ia.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(la(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(la(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var Ja=/^margin/,Ka=new RegExp("^("+$+")(?!px)[a-z%]+$","i"),La=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",pa.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,pa.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Ma(a,b,c){var d,e,f,g,h=a.style;return c=c||La(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ka.test(g)&&Ja.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Na(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Oa=/^(none|table(?!-c[ea]).+)/,Pa={position:"absolute",visibility:"hidden",display:"block"},Qa={letterSpacing:"0",fontWeight:"400"},Ra=["Webkit","Moz","ms"],Sa=d.createElement("div").style;function Ta(a){if(a in Sa)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ra.length;while(c--)if(a=Ra[c]+b,a in Sa)return a}function Ua(a,b,c){var d=_.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Va(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+aa[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+aa[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+aa[f]+"Width",!0,e))):(g+=r.css(a,"padding"+aa[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+aa[f]+"Width",!0,e)));return g}function Wa(a,b,c){var d,e=!0,f=La(a),g="border-box"===r.css(a,"boxSizing",!1,f);if(a.getClientRects().length&&(d=a.getBoundingClientRect()[b]),d<=0||null==d){if(d=Ma(a,b,f),(d<0||null==d)&&(d=a.style[b]),Ka.test(d))return d;e=g&&(o.boxSizingReliable()||d===a.style[b]),d=parseFloat(d)||0}return d+Va(a,b,c||(g?"border":"content"),e,f)+"px"}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Ma(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=a.style;return b=r.cssProps[h]||(r.cssProps[h]=Ta(h)||h),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=_.exec(c))&&e[1]&&(c=da(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b);return b=r.cssProps[h]||(r.cssProps[h]=Ta(h)||h),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Ma(a,b,d)),"normal"===e&&b in Qa&&(e=Qa[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Oa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?Wa(a,b,d):ca(a,Pa,function(){return Wa(a,b,d)})},set:function(a,c,d){var e,f=d&&La(a),g=d&&Va(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=_.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ua(a,c,g)}}}),r.cssHooks.marginLeft=Na(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Ma(a,"marginLeft"))||a.getBoundingClientRect().left-ca(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+aa[d]+b]=f[d]||f[d-2]||f[0];return e}},Ja.test(a)||(r.cssHooks[a+b].set=Ua)}),r.fn.extend({css:function(a,b){return S(this,function(a,b,c){var d,e,f={},g=0;if(r.isArray(b)){for(d=La(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function Xa(a,b,c,d,e){return new Xa.prototype.init(a,b,c,d,e)}r.Tween=Xa,Xa.prototype={constructor:Xa,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=Xa.propHooks[this.prop];return a&&a.get?a.get(this):Xa.propHooks._default.get(this)},run:function(a){var b,c=Xa.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Xa.propHooks._default.set(this),this}},Xa.prototype.init.prototype=Xa.prototype,Xa.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},Xa.propHooks.scrollTop=Xa.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=Xa.prototype.init,r.fx.step={};var Ya,Za,$a=/^(?:toggle|show|hide)$/,_a=/queueHooks$/;function ab(){Za&&(a.requestAnimationFrame(ab),r.fx.tick())}function bb(){return a.setTimeout(function(){Ya=void 0}),Ya=r.now()}function cb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=aa[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function db(a,b,c){for(var d,e=(gb.tweeners[b]||[]).concat(gb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function eb(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&ba(a),q=V.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],$a.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=V.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ga([a],!0),j=a.style.display||j,k=r.css(a,"display"),ga([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=V.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ga([a],!0),m.done(function(){p||ga([a]),V.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=db(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function fb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],r.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function gb(a,b,c){var d,e,f=0,g=gb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Ya||bb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:Ya||bb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(fb(k,j.opts.specialEasing);f<g;f++)if(d=gb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,db,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}r.Animation=r.extend(gb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return da(c.elem,a,_.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(K);for(var c,d=0,e=a.length;d<e;d++)c=a[d],gb.tweeners[c]=gb.tweeners[c]||[],gb.tweeners[c].unshift(b)},prefilters:[eb],prefilter:function(a,b){b?gb.prefilters.unshift(a):gb.prefilters.push(a)}}),r.speed=function(a,b,c){var e=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off||d.hidden?e.duration=0:e.duration="number"==typeof e.duration?e.duration:e.duration in r.fx.speeds?r.fx.speeds[e.duration]:r.fx.speeds._default,null!=e.queue&&e.queue!==!0||(e.queue="fx"),e.old=e.complete,e.complete=function(){r.isFunction(e.old)&&e.old.call(this),e.queue&&r.dequeue(this,e.queue)},e},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(ba).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=gb(this,r.extend({},a),f);(e||V.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=V.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&_a.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=V.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(cb(b,!0),a,d,e)}}),r.each({slideDown:cb("show"),slideUp:cb("hide"),slideToggle:cb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(Ya=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),Ya=void 0},r.fx.timer=function(a){r.timers.push(a),a()?r.fx.start():r.timers.pop()},r.fx.interval=13,r.fx.start=function(){Za||(Za=a.requestAnimationFrame?a.requestAnimationFrame(ab):a.setInterval(r.fx.tick,r.fx.interval))},r.fx.stop=function(){a.cancelAnimationFrame?a.cancelAnimationFrame(Za):a.clearInterval(Za),Za=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var hb,ib=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return S(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?hb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&r.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(K);
if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),hb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=ib[b]||r.find.attr;ib[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=ib[g],ib[g]=e,e=null!=c(a,b,d)?g:null,ib[g]=f),e}});var jb=/^(?:input|select|textarea|button)$/i,kb=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return S(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):jb.test(a.nodeName)||kb.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});var lb=/[\t\r\n\f]/g;function mb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,mb(this)))});if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=r.trim(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,mb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=r.trim(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,mb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(K)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=mb(this),b&&V.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":V.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+mb(c)+" ").replace(lb," ").indexOf(b)>-1)return!0;return!1}});var nb=/\r/g,ob=/[\x20\t\r\n\f]+/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":r.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(nb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:r.trim(r.text(a)).replace(ob," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type,g=f?null:[],h=f?e+1:d.length,i=e<0?h:f?e:0;i<h;i++)if(c=d[i],(c.selected||i===e)&&!c.disabled&&(!c.parentNode.disabled||!r.nodeName(c.parentNode,"optgroup"))){if(b=r(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(r.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var pb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!pb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,pb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(V.get(h,"events")||{})[b.type]&&V.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&T(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!T(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=V.access(d,b);e||d.addEventListener(a,c,!0),V.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=V.access(d,b)-1;e?V.access(d,b,e):(d.removeEventListener(a,c,!0),V.remove(d,b))}}});var qb=a.location,rb=r.now(),sb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var tb=/\[\]$/,ub=/\r?\n/g,vb=/^(?:submit|button|image|reset|file)$/i,wb=/^(?:input|select|textarea|keygen)/i;function xb(a,b,c,d){var e;if(r.isArray(b))r.each(b,function(b,e){c||tb.test(a)?d(a,e):xb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)xb(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(r.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)xb(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&wb.test(this.nodeName)&&!vb.test(a)&&(this.checked||!ha.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:r.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(ub,"\r\n")}}):{name:b.name,value:c.replace(ub,"\r\n")}}).get()}});var yb=/%20/g,zb=/#.*$/,Ab=/([?&])_=[^&]*/,Bb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Cb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Db=/^(?:GET|HEAD)$/,Eb=/^\/\//,Fb={},Gb={},Hb="*/".concat("*"),Ib=d.createElement("a");Ib.href=qb.href;function Jb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(K)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Kb(a,b,c,d){var e={},f=a===Gb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Lb(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Mb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Nb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:qb.href,type:"GET",isLocal:Cb.test(qb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Hb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Lb(Lb(a,r.ajaxSettings),b):Lb(r.ajaxSettings,a)},ajaxPrefilter:Jb(Fb),ajaxTransport:Jb(Gb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Bb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||qb.href)+"").replace(Eb,qb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(K)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Ib.protocol+"//"+Ib.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Kb(Fb,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Db.test(o.type),f=o.url.replace(zb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(yb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(sb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Ab,""),n=(sb.test(f)?"&":"?")+"_="+rb++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Hb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Kb(Gb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Mb(o,y,d)),v=Nb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Ob={0:200,1223:204},Pb=r.ajaxSettings.xhr();o.cors=!!Pb&&"withCredentials"in Pb,o.ajax=Pb=!!Pb,r.ajaxTransport(function(b){var c,d;if(o.cors||Pb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Ob[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Qb=[],Rb=/(=)\?(?=&|$)|\?\?/;r.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Qb.pop()||r.expando+"_"+rb++;return this[a]=!0,a}}),r.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Rb.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Rb.test(b.data)&&"data");if(h||"jsonp"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Rb,"$1"+e):b.jsonp!==!1&&(b.url+=(sb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||r.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Qb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),"script"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=B.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=oa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=r.trim(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&r.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?r("<div>").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length};function Sb(a){return r.isWindow(a)?a:9===a.nodeType&&a.defaultView}r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),d.width||d.height?(e=f.ownerDocument,c=Sb(e),b=e.documentElement,{top:d.top+c.pageYOffset-b.clientTop,left:d.left+c.pageXOffset-b.clientLeft}):d):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),r.nodeName(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||pa})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return S(this,function(a,d,e){var f=Sb(a);return void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Na(o.pixelPosition,function(a,c){if(c)return c=Ma(a,b),Ka.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return S(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.parseJSON=JSON.parse,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var Tb=a.jQuery,Ub=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Ub),b&&a.jQuery===r&&(a.jQuery=Tb),r},b||(a.jQuery=a.$=r),r});
(function() {
console.log('location', location, Cookies.get('atoken'))
if (!Cookies.get('atoken')) {
window.location.replace(window.location.href + 'login.html')
}
})()
\ No newline at end of file
const Axios = axios.create({
baseURL: window._CONF_.apiUrl,
timeout: 0,
withCredentials: true,
headers: {
"Content-Type": "application/json;charset=UTF-8"
}
})
Axios.interceptors.request.use(
config => {
// const atoken = Cookies.get('atoken')
// console.log('atoken', atoken)
// atoken && (config.headers.Authorization = atoken)
return config
},
error => {
return Promise.reject(error)
}
)
Axios.interceptors.response.use(
res => {
// if (res.data.enote || res.data.code === 401) {
// ELEMENT.MessageBox.alert('授权到期, 请重新登录', '提示', {
// confirmButtonText: '确定',
// callback: action => {
// console.log('action', action)
// window.location.replace(window.location.href + 'login.html')
// }
// });
// } else {
return Promise.resolve(res.data)
// }
},
error => {
console.error(error)
return Promise.reject(error)
}
)
function get(url, params = {}, config = {}) {
params['s'] = +new Date()
return Axios.get(url, {...config, params})
}
function post(url, params, config = {}) {
return Axios.post(url, params, config)
}
function deletes(url, params, config = {}) {
return Axios.delete(url, params, config)
}
function put(url, params, config = {}) {
return Axios.put(url, params, config)
}
This diff could not be displayed because it is too large.
const path = require('path')
const webpack = require('webpack')
const resolve = dir => {
return path.join(__dirname, dir)
}
// 项目部署基础
// 默认情况下,我们假设你的应用将被部署在域的根目录下,
// 例如:https://www.my-app.com/
// 默认:'/'
// 如果您的应用程序部署在子路径中,则需要在这指定子路径
// 例如:https://www.foobar.com/my-app/
// 需要将它改为'/my-app/'
const BASE_URL = process.env.NODE_ENV === 'production'
? './'
: '/'
console.log('process.env.NODE_ENV', process.env.NODE_ENV)
module.exports = {
// Project deployment base
// By default we assume your app will be deployed at the root of a domain,
// e.g. https://www.my-app.com/
// If your app is deployed at a sub-path, you will need to specify that
// sub-path here. For example, if your app is deployed at
// https://www.foobar.com/my-app/
// then change this to '/my-app/'
publicPath: BASE_URL,
lintOnSave: false,
// tweak internal webpack configuration.
// see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
chainWebpack: config => {
config.plugin('provide').use(webpack.ProvidePlugin, [
{
$: 'jquery',
jquery: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}
])
// config.resolve.alias
// .set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components'))
// .set('_c', resolve('src/components'))
// .set('_conf', resolve('config'))
// config.module
// .rule('view-design')
// .test(/view-design.src.*?js$/)
// .use('babel')
// .loader('babel-loader')
// .end()
},
// configureWebpack: config => {
// config.entry.app = ["@babel/polyfill", "./src/main.js"];
// },
// 打包时不生成.map文件
productionSourceMap: false,
// 这里写你调用接口的基础路径,来解决跨域,如果设置了代理,那你本地开发环境的axios的baseUrl要写为 '' ,即空字符串
devServer: {
proxy: {
'/malls': {
target: 'https://store.keliuyun.com/report/malls',
// changeOrigin: true
}
}
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!