From 95fc665771abeb335b29e6d59fe74d69cf9c446f Mon Sep 17 00:00:00 2001 From: hanbaoshan <hanbaoshan@aiotlink.com> Date: 星期四, 23 七月 2020 08:49:20 +0800 Subject: [PATCH] 首页更新,加入算法管理 --- public/images/app-mid/GB-config.png | 0 src/components/subComponents/FileUpload/list.vue | 42 public/images/app-mid/device.png | 0 public/images/app-mid/360.png | 0 src/components/subComponents/imgDown.vue | 93 src/pages/desktop/index/components/ToolsEntry.vue | 95 public/images/app-mid/data-push.png | 0 src/components/subComponents/IPInput.vue | 231 + src/pages/desktop/index/components/Dock.vue | 14 public/images/header-icon/SmartAI.png | 0 src/assets/img/desktop/desktop.png | 0 src/components/subComponents/CardItem.vue | 881 +++++++ src/pages/desktop/index/components/Tools.vue | 124 public/images/app-mid/monitor.png | 0 public/images/app-mid/vindicate.png | 0 src/components/subComponents/FileUpload/unsupport.vue | 30 src/components/subComponents/VueCron.vue | 194 + src/components/subComponents/FileUpload/file.vue | 452 +++ src/components/subComponents/FileUpload/btn.vue | 56 src/components/subComponents/RuleEditor.vue | 811 ++++++ src/components/subComponents/MultiRangeSlider.vue | 761 ++++++ public/images/header-icon/notice.png | 0 src/components/subComponents/LocalVedioList.vue | 129 + public/images/app-mid/library.png | 0 public/images/header-icon/help.png | 0 public/images/app-mid/scene-config.png | 0 public/images/app-mid/poll.png | 0 public/images/app-mid/algorithm-manage.png | 0 public/images/app-mid/search.png | 0 public/images/app-mid/DVR-access.png | 0 src/components/subComponents/BoardCard.vue | 135 + src/components/subComponents/ParticleNetwork.vue | 351 ++ src/pages/desktop/index/mock/userData.json | 7 public/images/app-mid/hashrate-manage.png | 0 src/components/subComponents/ModelCard.vue | 583 ++++ public/images/app-mid/log-manage.png | 0 public/images/app-mid/settings.png | 0 src/components/subComponents/FileUpload/common/mixins.js | 14 src/components/subComponents/FileUpload/drop.vue | 64 public/images/header-icon/search.png | 0 src/components/subComponents/FileUpload/index.vue | 230 + src/components/subComponents/eChartsBar.vue | 174 + public/images/logo.png | 0 src/components/subComponents/FileUpload/common/utils.js | 28 src/pages/index/app.vue | 5 src/components/subComponents/chartLiquid.vue | 141 + src/components/subComponents/FileUpload/uploader.vue | 155 + public/images/app-mid/camera-access.png | 0 src/pages/desktop/index/App.vue | 14 public/images/header-icon/system.png | 0 src/pages/algorithmManage/index/main.ts | 11 src/components/subComponents/FileUpload/common/file-events.js | 3 src/pages/algorithmManage/index/api.ts | 145 + src/pages/algorithmManage/index/App.vue | 861 +++++++ src/components/subComponents/DataStackCard.vue | 158 + package.json | 2 src/components/subComponents/FileUpload/files.vue | 42 src/components/subComponents/Card.vue | 163 + public/images/app-mid/algorithm-store.png | 0 src/components/subComponents/LocalVedioCard.vue | 139 + public/images/header-icon/user.png | 0 public/images/app-mid/datastack-config.png | 0 62 files changed, 7,285 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index 9dc2faf..e11d6ad 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "axios": "^0.19.2", "element-ui": "^2.4.6", "qs": "^6.9.4", + "simple-uploader.js": "^0.5.4", + "spark-md5": "^3.0.1", "vue": "^2.6.11", "vue-qrcode-component": "^2.1.1", "vuex": "^3.5.1" diff --git a/public/images/app-mid/360.png b/public/images/app-mid/360.png new file mode 100644 index 0000000..0bd5367 --- /dev/null +++ b/public/images/app-mid/360.png Binary files differ diff --git a/public/images/app-mid/DVR-access.png b/public/images/app-mid/DVR-access.png new file mode 100644 index 0000000..f99d3ac --- /dev/null +++ b/public/images/app-mid/DVR-access.png Binary files differ diff --git a/public/images/app-mid/GB-config.png b/public/images/app-mid/GB-config.png new file mode 100644 index 0000000..c315518 --- /dev/null +++ b/public/images/app-mid/GB-config.png Binary files differ diff --git a/public/images/app-mid/algorithm-manage.png b/public/images/app-mid/algorithm-manage.png new file mode 100644 index 0000000..d71f14a --- /dev/null +++ b/public/images/app-mid/algorithm-manage.png Binary files differ diff --git a/public/images/app-mid/algorithm-store.png b/public/images/app-mid/algorithm-store.png new file mode 100644 index 0000000..412f391 --- /dev/null +++ b/public/images/app-mid/algorithm-store.png Binary files differ diff --git a/public/images/app-mid/camera-access.png b/public/images/app-mid/camera-access.png new file mode 100644 index 0000000..35e41c7 --- /dev/null +++ b/public/images/app-mid/camera-access.png Binary files differ diff --git a/public/images/app-mid/data-push.png b/public/images/app-mid/data-push.png new file mode 100644 index 0000000..c4187c6 --- /dev/null +++ b/public/images/app-mid/data-push.png Binary files differ diff --git a/public/images/app-mid/datastack-config.png b/public/images/app-mid/datastack-config.png new file mode 100644 index 0000000..5d38c44 --- /dev/null +++ b/public/images/app-mid/datastack-config.png Binary files differ diff --git a/public/images/app-mid/device.png b/public/images/app-mid/device.png new file mode 100644 index 0000000..b0076d1 --- /dev/null +++ b/public/images/app-mid/device.png Binary files differ diff --git a/public/images/app-mid/hashrate-manage.png b/public/images/app-mid/hashrate-manage.png new file mode 100644 index 0000000..b755899 --- /dev/null +++ b/public/images/app-mid/hashrate-manage.png Binary files differ diff --git a/public/images/app-mid/library.png b/public/images/app-mid/library.png new file mode 100644 index 0000000..46681ff --- /dev/null +++ b/public/images/app-mid/library.png Binary files differ diff --git a/public/images/app-mid/log-manage.png b/public/images/app-mid/log-manage.png new file mode 100644 index 0000000..4c90102 --- /dev/null +++ b/public/images/app-mid/log-manage.png Binary files differ diff --git a/public/images/app-mid/monitor.png b/public/images/app-mid/monitor.png new file mode 100644 index 0000000..5fa6242 --- /dev/null +++ b/public/images/app-mid/monitor.png Binary files differ diff --git a/public/images/app-mid/poll.png b/public/images/app-mid/poll.png new file mode 100644 index 0000000..8773201 --- /dev/null +++ b/public/images/app-mid/poll.png Binary files differ diff --git a/public/images/app-mid/scene-config.png b/public/images/app-mid/scene-config.png new file mode 100644 index 0000000..096c1b7 --- /dev/null +++ b/public/images/app-mid/scene-config.png Binary files differ diff --git a/public/images/app-mid/search.png b/public/images/app-mid/search.png new file mode 100644 index 0000000..e122fc9 --- /dev/null +++ b/public/images/app-mid/search.png Binary files differ diff --git a/public/images/app-mid/settings.png b/public/images/app-mid/settings.png new file mode 100644 index 0000000..02b36db --- /dev/null +++ b/public/images/app-mid/settings.png Binary files differ diff --git a/public/images/app-mid/vindicate.png b/public/images/app-mid/vindicate.png new file mode 100644 index 0000000..038e685 --- /dev/null +++ b/public/images/app-mid/vindicate.png Binary files differ diff --git a/public/images/header-icon/SmartAI.png b/public/images/header-icon/SmartAI.png new file mode 100644 index 0000000..10b127b --- /dev/null +++ b/public/images/header-icon/SmartAI.png Binary files differ diff --git a/public/images/header-icon/help.png b/public/images/header-icon/help.png new file mode 100644 index 0000000..e66a57f --- /dev/null +++ b/public/images/header-icon/help.png Binary files differ diff --git a/public/images/header-icon/notice.png b/public/images/header-icon/notice.png new file mode 100644 index 0000000..ce93ca9 --- /dev/null +++ b/public/images/header-icon/notice.png Binary files differ diff --git a/public/images/header-icon/search.png b/public/images/header-icon/search.png new file mode 100644 index 0000000..b9ebcd8 --- /dev/null +++ b/public/images/header-icon/search.png Binary files differ diff --git a/public/images/header-icon/system.png b/public/images/header-icon/system.png new file mode 100644 index 0000000..4c37730 --- /dev/null +++ b/public/images/header-icon/system.png Binary files differ diff --git a/public/images/header-icon/user.png b/public/images/header-icon/user.png new file mode 100644 index 0000000..e97e46e --- /dev/null +++ b/public/images/header-icon/user.png Binary files differ diff --git a/public/images/logo.png b/public/images/logo.png new file mode 100644 index 0000000..dabfdaa --- /dev/null +++ b/public/images/logo.png Binary files differ diff --git a/src/assets/img/desktop/desktop.png b/src/assets/img/desktop/desktop.png new file mode 100644 index 0000000..7b9b347 --- /dev/null +++ b/src/assets/img/desktop/desktop.png Binary files differ diff --git a/src/components/subComponents/BoardCard.vue b/src/components/subComponents/BoardCard.vue new file mode 100644 index 0000000..ae1f688 --- /dev/null +++ b/src/components/subComponents/BoardCard.vue @@ -0,0 +1,135 @@ +<template> + <div class="board-card"> + <div class="top-text"> + <em>{{title}}</em> + <em style="color:#ff7733;font-size:13px">{{channelTotal}}</em> + </div> + <div class="bottom-icon"> + <div style="height:45%;" class="flex-center"> + <div class="right-bot-css"> + <el-tooltip effect="dark" placement="top"> + <div slot="content">鏈夎鍒�</div> + <span class="bottom-text"> + <i class="el-icon-success" style="color:#149A46;" v-show="ValidCount.length"></i> + {{ValidCount}} + </span> + </el-tooltip> + + <el-tooltip effect="dark" placement="top"> + <div slot="content">鏃犺鍒�</div> + <span class="bottom-text"> + <i class="el-icon-warning" style="color:orange;margin-left: 18px;" v-show="InValidCount.length"></i> + {{InValidCount}} + </span> + </el-tooltip> + </div> + </div> + <div style="width:100%;"> + <el-divider></el-divider> + </div> + <div style="height:45%;" class="flex-center"> + <div class="right-bot-css"> + <el-tooltip effect="dark" placement="top"> + <div slot="content">澶勭悊涓�</div> + <span class="bottom-text"> + <i class="iconfont iconzhengzaichuli" style="color:#3D68E1;font-size:18px;" v-show="RunningCount.length"></i> + {{RunningCount}} + </span> + </el-tooltip> + + <el-tooltip effect="dark" placement="top"> + <div slot="content">鏈鐞�</div> + <span class="bottom-text"> + <i class="iconfont iconchuli" title="鏈鐞�" style="margin-left:18px;font-size:18px;" v-show="NoDeal.length"></i> + {{NoDeal}} + </span> + </el-tooltip> + </div> + </div> + </div> + </div> +</template> + +<script> +export default { + name: "BoardCard", + props: { + title: { type: String, default: "" }, + total: { type: String, default: "" }, + ValidCount: { type: String, default: "" }, + InValidCount: { type: String, default: "" }, + RunningCount: { type: String, default: "" }, + channelTotal: { type: String, default: "" }, + NoDeal: { type: String, default: "" }, + width: { type: String, default: "126px"} + } +} +</script> +<style lang="scss"> +.board-card { + height: 120px; + width: 100%; + display: inline-block; + margin: 10px; + background: #ffffff; + border: 1px solid #e2e2e2; + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + border-radius: 4px; + cursor: pointer; + .top-text { + line-height: 30px; + font-family: PingFangSC-Medium; + font-size: 14px; + color: #222222; + } + .bottom-icon { + width: 100%; + height: calc(100% - 30px); + } + .mid-text { + margin-bottom: 18px; + font-family: PingFangSC-Medium; + font-size: 18px; + color: #ff7733; + } + .bottom-text { + position: relative; + top: 3px; + left: 1px; + color: #666666; + font-size: 13px; + } + em { + font-weight: 700; + } + hr { + background: rgb(226, 226, 226); + border: 0; + height: 1px; + } + i { + font-size: 20px; + } + .divider-css{ + height: 100%; + margin: 0; + } + .el-divider--horizontal { + display: block; + height: 1px; + width: 100%; + margin: 3px 0; + } + .right-top-css{ + margin: 0px auto; + position: relative; + } + .right-bot-css{ + margin: 0px auto; + position: relative; + } + .item { + margin: 4px; + } +} +</style> \ No newline at end of file diff --git a/src/components/subComponents/Card.vue b/src/components/subComponents/Card.vue new file mode 100644 index 0000000..7749870 --- /dev/null +++ b/src/components/subComponents/Card.vue @@ -0,0 +1,163 @@ +<template> + <el-card + class="my-card" + shadow="never" + :style="`height:${outHeight};width:${outWidth};max-height:160px;min-height:135px`" + :body-style="`height:${height};width:${width};`" + > + <el-carousel + ref="carousel" + :autoplay="false" + indicator-position="none" + :arrow="data.list.length > 1 ? 'always' : 'never'" + @change="changeHandle" + > + <el-carousel-item v-for="(item, index) in data.list" :key="index"> + <card-item + :data="item" + :showType="showType" + @detailsClick="detailsClick" + @addToBase="toAdd" + ></card-item> + </el-carousel-item> + </el-carousel> + </el-card> +</template> + +<script> +import CardItem from "./CardItem"; +export default { + components: { + CardItem + }, + props: { + data: { + type: Object, + default: null + }, + showType: { + type: String, + default: "" + }, + height: { + type: String, + default: "100%" + }, + width: { + type: String, + default: "100%" + }, + outHeight: { + type: String, + default: "100%" + }, + outWidth: { + type: String, + default: "100%" + } + }, + watch: { + + }, + data() { + return { + items: [], + filled: false + } + }, + watch: { + data(newVal) { + this.len = this.data.list.length; + if (this.len > 3) { + this.data.list = this.data.list.slice(0, 3) + } + } + }, + methods: { + detailsClick(ev) { + this.$emit("detailsClick", ev); + }, + toAdd(item) { + this.$emit("addToBase", item); + }, + changeHandle(e) { + // 鐐瑰嚮鍒囨崲鏃�, 浼氳Е鍙戣浜嬩欢, 姝ゆ椂閲嶆柊濉厖鍏ㄩ儴鏁版嵁, 缁勪欢浼氶噸鏂版覆鏌�, DOM鏇存柊鍚庢牴鎹偣鍑荤殑鎸夐挳,鎵嬪姩鍒囨崲 + // filled 鎺у埗鍙湪绗竴娆$偣鍑绘椂瑙﹀彂.鐒跺悗涓嶅啀骞查璺戦┈鐏垏鎹� + if (this.len > 3 && !this.filled) { + this.items = this.data.list + this.filled = true + + this.$nextTick(() => { + if (e == 1) { // 鐐瑰嚮浜嗕笅涓�寮� + this.$refs.carousel.next() + } + if (e == 2) { // 鐐瑰嚮浜嗕笂涓�寮� + this.$refs.carousel.prev() + } + }) + } + } + } +}; +</script> +<style lang="scss"> +.my-active-card { + border: 2px solid #ff7733 !important; + // background: rgba(145,197,255, 0.6) !important; +} +.my-card { + box-sizing: border-box; + padding: 12px 10px; + cursor: default; + .el-carousel__arrow { + top: 90%; + } + .el-carousel__arrow { + height: 20px; + width: 20px; + } + .el-carousel__arrow:hover { + background-color: rgba(102, 102, 102); + } + .el-card__body { + padding: 0px !important; + } + .el-card:hover { + box-sizing: border-box; + } + // .el-carousel__arrow { + // top: inherit; + // bottom: 0px; + // } + .el-carousel { + height: 100% !important; + width: 100%; + .el-carousel__container { + height: 100% !important; + width: 100%; + } + } +} +.my-card:hover { + -webkit-box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.3); + box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.3); +} +</style> +<style lang = "scss" scoped> +.el-carousel__container { + height: 100% !important; + .el-carousel__arrow { + top: 70% !important; + } + .el-carousel__arrow { + height: 20px; + width: 20px; + } + .el-carousel__arrow--right { + right: 10px !important; + } + .el-carousel__arrow--left { + left: 10px !important; + } +} +</style> diff --git a/src/components/subComponents/CardItem.vue b/src/components/subComponents/CardItem.vue new file mode 100644 index 0000000..e6abb97 --- /dev/null +++ b/src/components/subComponents/CardItem.vue @@ -0,0 +1,881 @@ +<template> + <div class="box-card" ref="cardItem"> + <!-- 宸︿晶鍥剧墖鍖哄煙 --> + <!-- 姣斿妯″紡 --> + <div class="s-card-left-isCompare" v-if="showType === 'compare' "> + <div class="card-img-box"> + <div class="card-img-box-compear"> + <div class="card-img-box-compear-left" ref="firstImg"> + <img + :src="'/httpImage/'+data.targetInfo[0].picSmUrl+'?width=160'" + :id="'/compear/'+data.targetInfo[0].picSmUrl" + class="cursor-pointer" + @click="detailsClick($event)" + /> + </div> + <el-carousel + @change="changeInitialIndex" + :initial-index="initialIndex" + :autoplay="false" + indicator-position="none" + :arrow="data.baseInfo.length > 1 ? 'always' : 'never'" + > + <el-carousel-item v-for="(item, index) in data.baseInfo" :key="index"> + <img + :src="'/httpImage/'+item.targetPicUrl+'?width=160'" + class="cursor-pointer" + @click="detailsClick($event)" + /> + </el-carousel-item> + </el-carousel> + </div> + <div + class="s-card-left-isCompare-div compareScore111" + style + :style="{ + bottom: getBottom(), + background: getUrl(data.baseInfo[initialIndex].bwType) + }" + > + <b>{{ `${data.baseInfo[initialIndex].compareScore}%` }}</b> + </div> + </div> + </div> + <!-- 鏅�氭ā寮� --> + <div v-else class="s-card-left"> + <!-- 姝e父鐨勬姄鎷嶅簱鍥剧墖 data.targetInfo == null 涓烘棤浜哄�煎畧 data.id == '' 涓哄姣斿嚭鏉ョ殑搴曞簱鍥剧墖--> + <div class="s-card-left-box" v-if="data.id !== ''"> + <el-carousel + trigger="click" + height="100%" + indicator-position="none" + v-if="data.picMaxUrl.length > 1" + :autoplay="false" + @change="changeCarousel" + > + <el-carousel-item v-for="(item, index) in data.picMaxUrl" :key="index + 'img'"> + <img + :src="'/httpImage/'+item+'?width=160'" + class="cursor-pointer" + @click="detailsClick($event)" + /> + </el-carousel-item> + </el-carousel> + <img + v-else-if="data.targetInfo == null || data.targetInfo[0].picSmUrl == ''" + :src="'/httpImage/'+data.picMaxUrl[0]+'?width=160'" + class="cursor-pointer" + @click="detailsClick($event)" + /> + <img + v-else + :src="'/httpImage/'+data.targetInfo[0].picSmUrl+'?width=160'" + class="cursor-pointer" + @click="detailsClick($event)" + /> + </div> + <div class="s-card-left-box" v-else> + <img :src="'/httpImage/'+data.baseInfo[0].targetPicUrl+'?width=160'" class="cursor-pointer" /> + </div> + </div> + <!-- 鍙充晶鏂囧瓧鍖哄煙 --> + <!-- 澶氬紶搴曞浘鍒囨崲 --> + <div class="s-card-right-isCompare" v-if="showType == 'compare'"> + <div + class="person" + :style="overflowState ? 'overflow: hidden' : 'overflow: auto'" + @mouseenter="cardMouseenter($event)" + @mouseleave="cardMouseleave($event)" + > + <!-- <p :title="data.baseInfo[0].compareScore" class="score"> + <span v-if="data.id">{{ data.compareScore }}%</span> + <span v-else>{{ data.baseInfo[0].compareScore }}%</span> + </p>--> + <p> + <span class="fontStyle color222">{{ data.picDate }}</span> + </p> + <p style="margin-bottom: 8px;"> + <span class="fontStyle color222">{{ data.cameraAddr }}</span> + </p> + <el-tooltip placement="right" popper-class="atooltip"> + <div slot="content"> + <p v-for="(item,index) in data.alarmRules" :key="index+'rule'"> + <span>{{data.taskName}}</span> + <span v-if="item.alarmLevel !== '鎾ら槻'"> {{item.alarmLevel}}</span> + <span v-if="item.linkInfo == '鑱斿姩浠诲姟'"> 鑱斿姩浠诲姟</span> + </p> + </div> + <el-button + style="line-height:17px;border:none;padding:0;overflow:hidden;text-overflow:ellipsis;cursor:default;width:100%;text-align:left" + > + <span + v-for="(item,index) in data.alarmRules" + :key="index+'rule1'" + style="text-overflow:ellipsis;max-width:100px" + > + <span class="fontStyle color666">{{data.taskName}}</span> + <span + class="fontStyle color666" + v-if="item.alarmLevel !== '鎾ら槻'" + > {{item.alarmLevel}}</span> + <span class="fontStyle color666" v-if="item.linkInfo == '鑱斿姩浠诲姟'"> 鑱斿姩浠诲姟</span> + <span v-if="index < data.alarmRules.length-1">/ </span> + </span> + </el-button> + </el-tooltip> + <el-tooltip placement="right" popper-class="atooltip"> + <div slot="content"> + <p> + <span + class="fontStyle" + v-if="data.baseInfo[initialIndex].tableName" + >{{ data.baseInfo[initialIndex].tableName }}</span> + <span + class="fontStyle" + v-if="data.baseInfo[initialIndex].targetName" + >/ {{ data.baseInfo[initialIndex].targetName }}</span> + <span + class="fontStyle" + v-if="data.baseInfo[initialIndex].labels" + >/ {{ data.baseInfo[initialIndex].labels.split("/")[1] }}</span> + <span + class="fontStyle" + v-if="data.baseInfo[initialIndex].monitorLevel" + >/ {{ data.baseInfo[initialIndex].monitorLevel }}</span> + </p> + </div> + <el-button + style="line-height:17px;border:none;padding:0;margin:0;overflow:hidden;text-overflow:ellipsis;cursor:default;width:100%;text-align:left" + > + <span + :style="data.baseInfo[initialIndex].bwType === '1' + ? 'color: red;font-size:12px;line-height:20px' + : 'font-size:12px;line-height:20px'" + > + <span + class="fontStyle" + v-if="data.baseInfo[initialIndex].tableName" + >{{ data.baseInfo[initialIndex].tableName }}</span> + <span + class="fontStyle" + v-if="data.baseInfo[initialIndex].targetName" + >/ {{ data.baseInfo[initialIndex].targetName }}</span> + <span + class="fontStyle" + v-if="data.baseInfo[initialIndex].labels" + >/ {{ data.baseInfo[initialIndex].labels.split("/")[1] }}</span> + <span + class="fontStyle" + v-if="data.baseInfo[initialIndex].monitorLevel" + >/ {{ data.baseInfo[initialIndex].monitorLevel }}</span> + </span> + </el-button> + </el-tooltip> + </div> + <div class="card-icon-box"> + <el-tooltip content="璇︽儏" placement="top" popper-class="atooltip"> + <i class="iconfont iconcaidan" @click="detailsClick($event)"></i> + </el-tooltip> + <el-tooltip content="鏌ユ壘姝や汉" placement="top" popper-class="atooltip"> + <i class="iconfont iconsousuoren" @click="tosearch(data)"></i> + </el-tooltip> + <el-tooltip content="鍔犲叆搴曞簱" placement="top" popper-class="atooltip"> + <i class="iconfont icontianjiaren" @click="toAdd(data)"></i> + </el-tooltip> + <el-tooltip content="鏀惰棌" placement="top" popper-class="atooltip"> + <i class="iconfont iconshoucang2"></i> + </el-tooltip> + </div> + </div> + <!-- 搴曞簱浜哄憳妯″紡 --> + <div v-else-if="data.id == ''" class="s-card-right-isCompare"> + <div + class="person" + :style="overflowState ? 'overflow: hidden' : 'overflow: auto'" + @mouseenter="cardMouseenter($event)" + @mouseleave="cardMouseleave($event)" + > + <p + :title="data.baseInfo[0].compareScore" + class="score" + style="font-family: PingFangSC-Medium;font-size: 20px;color: #3D68E1;letter-spacing: 0.4px;" + > + <span>{{ data.baseInfo[0].compareScore }}%</span> + </p> + <p + :style="data.baseInfo[0].bwType == '0' ? 'font-size:12px;line-height:20px' : 'color:red;font-size:12px;line-height:20px'" + >{{ data.baseInfo[0].tableName }}</p> + <p :style="data.baseInfo[0].bwType == '0' ? '' : 'color:red'"> + <span>{{ data.baseInfo[0].targetName }}</span> + <span + v-if="data.baseInfo[0].labels" + >/ {{ data.baseInfo[0].labels.split("/")[1] }}</span> + </p> + </div> + <div class="card-icon-box"> + <el-tooltip content="鏌ユ壘姝や汉" placement="top" popper-class="atooltip" style="margin-left:10px"> + <i class="iconfont iconsousuoren" @click="tosearch(data)" title="鏌ユ壘姝や汉"></i> + </el-tooltip> + </div> + </div> + <!-- 娌℃湁搴曞簱 16锛�9鍥剧墖 鏈�姝e父鐨剏olo鎶撴媿 鏃犱汉鍊煎畧 姝e父yolo鎶撴媿娌℃湁灏忓浘--> + <div + v-else-if="data.targetInfo == null || data.targetInfo[0].picSmUrl == ''" + class="s-card-right-signal" + > + <div + class="signal-img-dev" + :style="overflowState ? 'overflow: hidden' : 'overflow: auto'" + @mouseenter="cardMouseenter($event)" + @mouseleave="cardMouseleave($event)" + > + <p :title="data.picDate"> + <span class="fontStyle color222">{{ data.picDate }}</span> + </p> + <p :title="data.cameraAddr" style="margin-bottom: 8px;"> + <span class="fontStyle color222">{{ data.cameraAddr }}</span> + </p> + <el-tooltip placement="right" popper-class="atooltip"> + <div slot="content"> + <p v-for="(item,index) in data.alarmRules" :key="index+'rule'"> + <span>{{data.taskName}}</span> + <span v-if="item.alarmLevel !== '鎾ら槻'">{{item.alarmLevel}}</span> + <span v-if="item.linkInfo == '鑱斿姩浠诲姟'"> 鑱斿姩浠诲姟</span> + </p> + </div> + <el-button + style="border:none;padding:0;overflow:hidden;text-overflow:ellipsis;cursor:default;width:100%;text-align:left" + > + <span + v-for="(item,index) in data.alarmRules" + :key="index+'rule1'" + style="text-overflow:ellipsis;max-width:100px" + > + <span class="fontStyle color666">{{data.taskName}}</span> + <span + class="fontStyle color666" + v-if="item.alarmLevel !== '鎾ら槻'" + >{{item.alarmLevel}}</span> + <span class="fontStyle color666" v-if="item.linkInfo == '鑱斿姩浠诲姟'"> 鑱斿姩浠诲姟</span> + <span v-if="index < data.alarmRules.length-1">/ </span> + </span> + </el-button> + </el-tooltip> + </div> + <div class="right-bottom"> + <div v-if="!data.id" class="card-icon-box"> + <!-- <i class="iconfont systemxing ml50" title="鏀惰棌" ></i> --> + <el-tooltip content="鏌ユ壘姝や汉" placement="top" popper-class="atooltip"> + <i class="iconfont iconsousuoren ml50" @click="tosearch(data)"></i> + </el-tooltip> + </div> + <div + v-if="data.targetInfo == null || data.targetInfo[0].picSmUrl == ''" + class="card-icon-box" + > + <el-tooltip content="璇︽儏" placement="top" popper-class="atooltip"> + <i class="iconfont iconcaidan" @click="detailsClick($event)"></i> + </el-tooltip> + <el-tooltip content="鏀惰棌" placement="top" popper-class="atooltip"> + <i class="iconfont iconshoucang2" @click="dialogVisible = true"></i> + </el-tooltip> + <!-- :class=" + data.isAlarm ? 'iconfont systemmm' : 'iconfont systemxing' + "--> + </div> + <div class="card-icon-box" v-else> + <el-tooltip content="璇︽儏" placement="top" popper-class="atooltip"> + <i class="iconfont iconcaidan" @click="detailsClick($event)"></i> + </el-tooltip> + <el-tooltip content="鏌ユ壘姝や汉" placement="top" popper-class="atooltip"> + <i class="iconfont iconsousuoren" @click="tosearch(data)"></i> + </el-tooltip> + <el-tooltip content="鍔犲叆搴曞簱" placement="top" popper-class="atooltip"> + <i class="iconfont icontianjiaren" @click="toAdd(data)"></i> + </el-tooltip> + <el-tooltip content="鏀惰棌" placement="top" popper-class="atooltip"> + <i class="iconfont iconshoucang2" @click="dialogVisible = true"></i> + </el-tooltip> + </div> + </div> + </div> + + <!-- 娌℃湁搴曞簱锛岄潪姣斿锛屾櫘閫氭ā寮� 涓�瀹氭湁targetInfo锛屽苟涓攖argetInfo涓暟涓�1--> + <div + v-else-if="data.targetInfo !== null && data.targetInfo[0].picSmUrl !== '' && data.targetInfo.length == 1" + class="s-card-right-signal" + > + <div + class="signal-img-dev" + :style="overflowState ? 'overflow: hidden' : 'overflow: auto'" + @mouseenter="cardMouseenter($event)" + @mouseleave="cardMouseleave($event)" + > + <p + class="score" + v-if="VideoPhotoData.uploadType" + style="font-family: PingFangSC-Medium;font-size: 20px;color: #3D68E1;letter-spacing: 0.4px;" + > + <span v-if="data.id">{{ data.compareScore }}%</span> + <span v-else>{{ data.baseInfo[0].compareScore }}%</span> + </p> + <p :title="data.picDate"> + <span class="fontStyle color222">{{ data.picDate }}</span> + </p> + <p :title="data.cameraAddr" style="margin-bottom: 8px;"> + <span class="fontStyle color222">{{ data.cameraAddr }}</span> + </p> + <el-tooltip placement="right" popper-class="atooltip" v-if="!VideoPhotoData.uploadType"> + <div slot="content"> + <p v-for="(item,index) in data.alarmRules" :key="index+'rule2'"> + <span class="fontStyle">{{data.taskName}}</span> + <span + class="fontStyle" + v-if="item.alarmLevel !== '鎾ら槻'" + >{{item.alarmLevel}}</span> + <span v-if="item.linkInfo == '鑱斿姩浠诲姟'" class="fontStyle"> 鑱斿姩浠诲姟</span> + <span v-if="index < data.alarmRules.length-1">/ </span> + </p> + </div> + <el-button + style="border:none;padding:0;margin:0px;overflow:hidden;text-overflow:ellipsis;cursor:default;width:100%;text-align:left" + > + <span v-for="(item,index) in data.alarmRules" :key="index+'rule3'"> + <span class="fontStyle color666">{{data.taskName}}</span> + <span + class="fontStyle color666" + v-if="item.alarmLevel !== '鎾ら槻'" + >{{item.alarmLevel}}</span> + <span v-if="item.linkInfo == '鑱斿姩浠诲姟'" class="fontStyle color666"> 鑱斿姩浠诲姟</span> + <span v-if="index < data.alarmRules.length-1">/ </span> + </span> + </el-button> + </el-tooltip> + <!-- <p> + <span class="fontStyle color666">{{ data.sex }}</span> / <span class="fontStyle color666">{{ data.ageDescription }}</span> / <span class="fontStyle color666">{{ data.race }}</span> + </p>--> + <el-tooltip + placement="right" + popper-class="atooltip" + v-if="data.baseInfo && data.baseInfo[0].targetName != ''" + > + <div slot="content"> + <p v-for="(item,index) in data.baseInfo" :key="index+'base1'"> + <span class="fontStyle">{{item.tableName}}</span> + <span class="fontStyle" v-if="item.targetName !== ''">/ {{item.targetName}}</span> + <span + class="fontStyle" + v-if="item.labels !== '' && item.labels.split('/')[1] !== ''" + >/ {{item.labels.split("/")[1]}}</span> + <span + class="fontStyle" + v-if="item.labels !== '' && item.labels.split('/')[0] !== ''" + >/ {{item.labels.split("/")[0]}}</span> + </p> + </div> + <el-button + style="border:none;padding:0;margin:0px;overflow:hidden;text-overflow:ellipsis;cursor:default;width:100%;text-align:left" + > + <span + v-for="(item,index) in data.baseInfo" + :key="index+'base'" + :style="item.bwType == '1' ? 'color:red;font-size:12px;line-height:20px':'font-size:12px;line-height:20px'" + > + <span class="fontStyle">{{item.tableName}}</span> + <span class="fontStyle" v-if="item.targetName !== ''">/ {{item.targetName}}</span> + <span + class="fontStyle" + v-if="item.labels !== '' && item.labels.split('/')[1] !== ''" + >/ {{item.labels.split("/")[1]}}</span> + <span + class="fontStyle" + v-if="item.labels !== '' && item.labels.split('/')[0] !== ''" + >/ {{item.labels.split("/")[0]}}</span> + </span> + </el-button> + </el-tooltip> + + <el-tooltip + placement="right" + popper-class="atooltip" + v-if="data.baseInfo == null" + style="margin-top:5px" + > + <div slot="content"> + <span :style="'color:red;font-size:14px;line-height:20px'">{{data.showLabels}}</span> + </div> + <el-button + style="border:none;padding:0;margin:0px;overflow:hidden;text-overflow:ellipsis;cursor:default;width:100%;text-align:left" + > + <span :style=" 'color:red;font-size:14px;line-height:20px'">{{data.showLabels}}</span> + </el-button> + </el-tooltip> + </div> + <div class="right-bottom"> + <div v-if="!data.id" class="card-icon-box"> + <!-- 搴曞簱浜哄憳 --> + <!-- <i class="iconfont systemxing ml50" title="鏀惰棌" ></i> --> + <el-tooltip content="鏌ユ壘姝や汉" placement="top" popper-class="atooltip"> + <i class="iconfont iconsousuoren ml50" @click="tosearch(data)"></i> + </el-tooltip> + </div> + <div v-if="data.targetInfo[0].picSmUrl == ''" class="card-icon-box"> + <!-- yolo --> + <el-tooltip content="璇︽儏" placement="top" popper-class="atooltip"> + <i class="iconfont iconcaidan" @click="detailsClick($event)"></i> + </el-tooltip> + <el-tooltip content="鏀惰棌" placement="top" popper-class="atooltip"> + <i class="iconfont iconshoucang2"></i> + </el-tooltip> + <!-- :class=" + data.isAlarm ? 'iconfont systemmm' : 'iconfont systemxing' + "--> + </div> + <div class="card-icon-box" v-else> + <!-- 姝e父浜鸿劯 --> + <el-tooltip content="璇︽儏" placement="top" popper-class="atooltip"> + <i class="iconfont iconcaidan" @click="detailsClick($event)"></i> + </el-tooltip> + <el-tooltip + content="鏌ユ壘姝や汉" + placement="top" + popper-class="atooltip" + v-if="data.targetInfo[0].targetType == 'FaceDetect'" + > + <i class="iconfont iconsousuoren" @click="tosearch(data)"></i> + </el-tooltip> + <el-tooltip + content="鍔犲叆搴曞簱" + placement="top" + popper-class="atooltip" + v-if="data.targetInfo[0].targetType == 'FaceDetect'" + > + <i class="iconfont icontianjiaren" @click="toAdd(data)"></i> + </el-tooltip> + <el-tooltip content="鏀惰棌" placement="top" popper-class="atooltip"> + <i class="iconfont iconshoucang2"></i> + </el-tooltip> + </div> + </div> + </div> + <!-- 鎸佺画鏃堕棿妯″紡锛屽寮犲浘 --> + <div v-else class="s-card-right-double"> + <transition name="fade"> + <div + class="double-person" + :style="overflowState ? 'overflow: hidden' : 'overflow: auto'" + @mouseenter="cardMouseenter($event)" + @mouseleave="cardMouseleave($event)" + > + <div> + <p :title="data.picDate"> + <span class="fontStyle color222">{{ data.picDate }}</span> + </p> + <p :title="data.cameraAddr" style="margin-bottom: 8px;"> + <span class="fontStyle color222">{{ data.cameraAddr }}</span> + </p> + <p v-for="(item,index) in data.alarmRules" :key="index+'rule'"> + <span class="fontStyle color666">{{data.taskName}}</span> / + <span class="fontStyle color666">{{item.alarmLevel}}</span> / + <span v-if="item.linkInfo == '鑱斿姩浠诲姟'" class="fontStyle color666">鑱斿姩浠诲姟</span> + <span v-if="index < data.alarmRules.length-1">/ </span> + </p> + </div> + </div> + </transition> + </div> + </div> +</template> + +<script> +import cardType from "../../mockData/cardType.ts"; +import bus from "@/main"; + +export default { + mounted() { + bus.$on('refreshCompareImg', () => { + // this.tempShowType = false + }) + window.addEventListener("resize", this.watchWindow); + }, + props: { + data: { + type: Object, + default: null + }, + showType: { + type: String, + default: "search" + } + }, + watch: { + data: { + handler(val, oldVal) { + console.log('鏁版嵁鍙戠敓鍙樺寲') + this.$forceUpdate() + }, + deep: true + } + }, + computed: { + isId() { + return this.data.id + } + }, + data() { + return { + tempShowType: true, + initialIndex: 0, + cardType, + carouselIndex: 0, + dialogVisible: false, + overflowState: true + }; + }, + methods: { + watchWindow() { + // console.log('height') + // this.$nextTick(() => { + // document.querySelectorAll('.compareScore111').forEach(ele => { + // ele.style.bottom = this.getBottom() + // console.log("鍏冪礌鐨勬牱寮忓�硷細",ele.style.bottom) + // }); + // this.$forceUpdate() + // }) + }, + getBottom() { + // let imgDom = document.getElementById(str) + let imgDom = this.$refs.firstImg + if (imgDom) { + let num = (imgDom.offsetHeight - imgDom.offsetWidth) / 2 + return `${num}px`; + } + return `4px`; + }, + getUrl(bwtype) { + if (bwtype == 1) { + return `url(${require("@/assets/bg/red.png")})` + } else { + return `url(${require("@/assets/bg/green.png")})` + } + }, + changeInitialIndex(index) { + this.initialIndex = index; + }, + cardMouseenter(ev) { + this.overflowState = false; + }, + cardMouseleave(ev) { + this.overflowState = true; + }, + changeCarousel(index) { + this.carouselIndex = index; + }, + detailsClick(ev) { + this.$emit("detailsClick", ev); + }, + toAdd(item) { + console.log("瑙﹀彂鍔犲叆搴曞簱") + this.$emit("addToBase", item); + }, + tosearch(item) { + var curWwwPath = window.document.location.href; + var pathname = window.document.location.pathname; + var pos = curWwwPath.indexOf(pathname); + var localhostPath = curWwwPath.substring(0, pos); //ip+port + var href = localhostPath + "/Layout/Searching" + let captureId = item.id == "" ? item.baseInfo[0].targetId : item.id + var url = item.targetInfo ? item.targetInfo[0].picSmUrl : item.baseInfo[0].targetPicUrl + console.log("璺宠浆鍦板潃", href, "url", url) + var compType = 1 // 鏁版嵁鏉ヨ嚜浜巈s + if (!item.id || item.id == "") { + compType = 0 // 鏁版嵁鏉ヨ嚜浜庡簳搴� + } + window.open(href + '?showType=findByPic&targetId=' + captureId + '&picSmUrl=' + url + '&compType=' + compType) + } + } +}; +</script> +<style lang="scss"> +.fontStyle { + font-family: PingFangSC-Medium; +} +.color222 { + font-size: 0.75rem; + font-weight: 600; + line-height: 1rem; + color: #222222; +} +.color666 { + color: #666666; + font-size: 0.75rem; + line-height: 1.25rem; +} +.box-card { + cursor: default; + .el-carousel__arrow { + height: 20px; + width: 20px; + } + height: 100%; + .el-card__body { + height: 100%; + padding: 5px; + box-sizing: border-box; + } + .s-card-left-isCompare { + float: left; + height: 100%; + width: calc(60% - 10px); + margin-right: 10px; + .card-img-box { + box-sizing: border-box; + width: 100%; + height: 100%; + position: relative; + overflow: hidden; + .card-img-box-compear { + height: 100%; + width: 100%; + display: flex; + .card-img-box-compear-left { + display: inline-block; + display: flex; + justify-content: center; + align-items: Center; + overflow: hidden; + width: 100%; + height: 100%; + } + .el-carousel__item { + display: flex; + justify-content: center; + align-items: Center; + overflow: hidden; + } + .el-carousel__container { + height: 100% !important; + .el-carousel__arrow { + top: 50% !important; + } + .el-carousel__arrow { + height: 20px; + width: 20px; + } + .el-carousel__arrow--right { + right: 5px !important; + } + .el-carousel__arrow--left { + left: 5px !important; + } + } + } + } + .card-icon-box { + width: 100%; + text-align: left; + position: absolute; + bottom: 0px; + i { + font-size: 20px !important; + padding-right: 10px; + cursor: pointer; + } + } + img { + width: 100%; + height: 100%; + object-fit: contain; + } + .s-card-left-isCompare-div { + width: 60px; + position: absolute; + left: calc(50% - 35px); + bottom: 16px; + padding: 0px 8px; + height: 20px; + line-height: 20px; + color: white; + //background-color: red; + z-index: 2; + border-top-right-radius: 5px; + border-top-left-radius: 5px; + background-size: 100% 100%; + } + } + .s-card-left { + float: left; + height: 100%; + width: calc(50% - 10px); + margin-right: 10px; + .s-card-left-box { + overflow: hidden; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + .el-carousel__arrow { + top: 50%; + bottom: inherit; + } + } + .card-icon-box { + height: 30px; + width: 100%; + text-align: left; + margin-left: 10px; + padding-top: 10px; + i { + color: #3d68e1; + font-size: 20px !important; + padding-right: 10px; + cursor: pointer; + } + } + .el-carousel { + height: 100%; + width: 100%; + .el-carousel__container { + height: 100 !important; + width: 100%; + } + .el-carousel__item { + display: flex; + justify-content: center; + align-items: center; + background-color: #fff; + } + } + img { + width: 100%; + height: 100%; + object-fit: contain; + } + } + .s-card-right-isCompare { + width: 40%; + height: 100%; + float: left; + padding-left: 10px; + box-sizing: border-box; + position: relative; + .active-pull { + height: 100% !important; + overflow: auto !important; + position: relative; + z-index: 1; + } + .overflow { + overflow: auto !important; + } + .person { + height: calc(100% - 25px); + overflow: hidden; + background-color: #fff; + text-align: left; + .score { + font-size: 25px; + } + p { + width: 100%; + overflow: hidden; + padding: 3px 0px; + text-overflow: ellipsis; + white-space: nowrap; + // cursor: pointer; + b { + display: inline-block; + width: 48px; + } + } + } + .card-icon-box { + width: 100%; + text-align: left; + position: absolute; + bottom: 0px; + i { + color: #3d68e1; + font-size: 20px !important; + padding-right: 10px; + cursor: pointer; + } + } + } + .s-card-right-signal { + width: 50%; + height: 100%; + float: left; + overflow: hidden; + background-color: #fff; + text-align: left; + padding-left: 10px; + box-sizing: border-box; + position: relative; + .el-carousel__arrow { + top: 50%; + } + p { + width: 100%; + overflow: hidden; + padding: 3px 0px; + text-overflow: ellipsis; + // cursor: pointer; + white-space: nowrap; + b { + display: inline-block; + width: 48px; + } + } + .signal-img-dev { + height: 100%; + width: 100%; + //overflow: auto; + } + .right-bottom { + width: 100%; + text-align: left; + position: absolute; + bottom: 0px; + i { + color: #3d68e1; + font-size: 20px !important; + padding-right: 10px; + cursor: pointer; + } + } + } + .s-card-right-double { + width: 50%; + height: 100%; + float: left; + overflow: hidden; + background-color: #fff; + text-align: left; + box-sizing: border-box; + .double-person { + padding: 10px; + box-sizing: border-box; + overflow: auto; + p { + width: 100%; + overflow: hidden; + padding: 3px 0px; + text-overflow: ellipsis; + white-space: nowrap; + // cursor: pointer; + b { + display: inline-block; + width: 48px; + } + } + } + .double-person, + div { + height: 100%; + width: 100%; + } + } +} +</style> diff --git a/src/components/subComponents/DataStackCard.vue b/src/components/subComponents/DataStackCard.vue new file mode 100644 index 0000000..0cd0054 --- /dev/null +++ b/src/components/subComponents/DataStackCard.vue @@ -0,0 +1,158 @@ +<template> + <div class="s-board-card flex-center"> + <div style="width:38%;"> + <div class="top-text"> + <em>{{title}}</em> + </div> + <div class="mid-text"> + <em>{{total}}</em> + </div> + </div> + <div style="height:86px;"> + <el-divider class="divider-css" direction="vertical"></el-divider> + </div> + <div style="width:61%;height:100%;"> + <div style="height:50%;" class="flex-center right-bot-css"> + <el-tooltip effect="dark" placement="top"> + <div slot="content">鍏ㄩ儴鎵撳紑鍒嗘瀽寮�鍏�</div> + <span class="bottom-text"> + <i class="iconfont iconquanbu" style="color:#3D68E1;" v-show="ValidCount.length"></i> + {{ValidCount}} + </span> + </el-tooltip> + + <el-tooltip effect="dark" placement="top"> + <div slot="content">绠楁硶閰嶇疆涓嶅叏</div> + <span class="bottom-text"> + <i + class="iconfont iconicon-test6" + style="color:#3D68E1;margin-left: 15px;" + v-show="InValidCount.length" + ></i> + {{InValidCount}} + </span> + </el-tooltip> + </div> + <div style="width:100%;"> + <el-divider></el-divider> + </div> + <div style="height:40%;" class="flex-center right-bot-css"> + <el-tooltip effect="dark" placement="top"> + <div slot="content">姝e湪鎵ц鍒嗘瀽澶勭悊</div> + <span class="bottom-text"> + <i class="iconfont iconicon-test11" style="color:#3D68E1" v-show="RunningCount.length"></i> + {{RunningCount}} + </span> + </el-tooltip> + + <el-tooltip effect="dark" placement="top"> + <div slot="content">{{fourTip}}</div> + <span class="bottom-text"> + <i + :class="`iconfont ${fourIcon}`" + style="color:#3D68E1;margin-left:15px;" + v-show="NoDeal.length" + ></i> + {{NoDeal}} + </span> + </el-tooltip> + </div> + </div> + </div> +</template> + +<script> +export default { + name: "BoardCard", + props: { + title: { type: String, default: "" }, + total: { type: String, default: "" }, + ValidCount: { type: String, default: "" }, + InValidCount: { type: String, default: "" }, + RunningCount: { type: String, default: "" }, + NoDeal: { type: String, default: "" }, + width: { type: String, default: "126px" }, + fourTip: { type: String, default: "" }, + fourIcon: { type: String, default: "" } + } +} +</script> +<style lang="scss"> +.s-board-card { + height: 120px; + width: 100%; + display: inline-block; + margin: 10px; + background: #ffffff; + border: 1px solid #e2e2e2; + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + border-radius: 4px; + cursor: pointer; + .top-text { + line-height: 30px; + font-family: PingFangSC-Medium; + font-size: 14px; + color: #222222; + } + .mid-text { + margin-bottom: 18px; + font-family: PingFangSC-Medium; + font-size: 18px; + color: #ff7733; + } + .bottom-text { + word-break: keep-all; + text-align: right; + // position: relative; + // top: 3px; + // left: 1px; + // color: #666666; + // font-size: 13px; + } + em { + font-weight: 700; + } + hr { + background: rgb(226, 226, 226); + border: 0; + height: 1px; + } + i { + font-size: 20px; + } + .divider-css { + height: 100%; + margin: 0; + } + .el-divider--horizontal { + display: block; + height: 1px; + width: 100%; + margin: 3px 0; + } + .right-top-css { + margin: 0px auto; + position: relative; + } + .right-bot-css { + margin: 0px 5px; + position: relative; + } + .out-div-33 { + width: 33%; + height: 100%; + .txt-css { + width: 100%; + height: 50%; + position: relative; + top: 30px; + } + .icon-css { + width: 100%; + height: 30%; + margin-top: 10px; + position: relative; + } + } +} +</style> \ No newline at end of file diff --git a/src/components/subComponents/FileUpload/btn.vue b/src/components/subComponents/FileUpload/btn.vue new file mode 100644 index 0000000..7ea24ff --- /dev/null +++ b/src/components/subComponents/FileUpload/btn.vue @@ -0,0 +1,56 @@ +<template> + <label class="uploader-btn" ref="btn" v-show="support"> + <slot></slot> + </label> +</template> + +<script> +import { uploaderMixin, supportMixin } from './common/mixins' + +const COMPONENT_NAME = 'uploader-btn' + +export default { + name: COMPONENT_NAME, + mixins: [uploaderMixin, supportMixin], + props: { + directory: { + type: Boolean, + default: false + }, + single: { + type: Boolean, + default: false + }, + attrs: { + type: Object, + default() { + return {} + } + } + }, + mounted() { + this.$nextTick(() => { + this.uploader.uploader.assignBrowse(this.$refs.btn, this.directory, this.single, this.attrs) + }) + } +} +</script> + +<style> +.uploader-btn { + display: inline-block; + position: relative; + padding: 4px 8px; + font-size: 100%; + line-height: 1.4; + color: #666; + border: 1px solid #666; + cursor: pointer; + border-radius: 2px; + background: none; + outline: none; +} +.uploader-btn:hover { + background-color: rgba(0, 0, 0, 0.08); +} +</style> diff --git a/src/components/subComponents/FileUpload/common/file-events.js b/src/components/subComponents/FileUpload/common/file-events.js new file mode 100644 index 0000000..2aba807 --- /dev/null +++ b/src/components/subComponents/FileUpload/common/file-events.js @@ -0,0 +1,3 @@ +const events = ['fileProgress', 'fileSuccess', 'fileComplete', 'fileError'] + +export default events diff --git a/src/components/subComponents/FileUpload/common/mixins.js b/src/components/subComponents/FileUpload/common/mixins.js new file mode 100644 index 0000000..efab3b0 --- /dev/null +++ b/src/components/subComponents/FileUpload/common/mixins.js @@ -0,0 +1,14 @@ +export const uploaderMixin = { + inject: ['uploader'] +} + +export const supportMixin = { + data () { + return { + support: true + } + }, + mounted () { + this.support = this.uploader.uploader.support + } +} diff --git a/src/components/subComponents/FileUpload/common/utils.js b/src/components/subComponents/FileUpload/common/utils.js new file mode 100644 index 0000000..92c775a --- /dev/null +++ b/src/components/subComponents/FileUpload/common/utils.js @@ -0,0 +1,28 @@ +export function secondsToStr(temp) { + const years = Math.floor(temp / 31536000) + if (years) { + return years + ' 骞�' + numberEnding(years) + } + const days = Math.floor((temp %= 31536000) / 86400) + if (days) { + return days + ' 澶�' + numberEnding(days) + } + const hours = Math.floor((temp %= 86400) / 3600) + if (hours) { + return hours + ' 灏忔椂' + numberEnding(hours) + } + const minutes = Math.floor((temp %= 3600) / 60) + if (minutes) { + return minutes + ' 鍒�' + numberEnding(minutes) + } + const seconds = temp % 60 + return seconds + ' 绉�' + numberEnding(seconds) + function numberEnding(number) { + // return (number > 1) ? 's' : '' + return '' + } +} + +export function kebabCase(s) { + return s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`) +} diff --git a/src/components/subComponents/FileUpload/drop.vue b/src/components/subComponents/FileUpload/drop.vue new file mode 100644 index 0000000..9c88666 --- /dev/null +++ b/src/components/subComponents/FileUpload/drop.vue @@ -0,0 +1,64 @@ +<template> + <div class="uploader-drop" :class="dropClass" ref="drop" v-show="support"> + <slot></slot> + </div> +</template> + +<script> +import { uploaderMixin, supportMixin } from './common/mixins' + +const COMPONENT_NAME = 'uploader-drop' + +export default { + name: COMPONENT_NAME, + mixins: [uploaderMixin, supportMixin], + data() { + return { + dropClass: '' + } + }, + methods: { + onDragEnter() { + this.dropClass = 'uploader-dragover' + }, + onDragLeave() { + this.dropClass = '' + }, + onDrop() { + this.dropClass = 'uploader-droped' + } + }, + mounted() { + this.$nextTick(() => { + const dropEle = this.$refs.drop + const uploader = this.uploader.uploader + uploader.assignDrop(dropEle) + uploader.on('dragenter', this.onDragEnter) + uploader.on('dragleave', this.onDragLeave) + uploader.on('drop', this.onDrop) + }) + }, + beforeDestroy() { + const dropEle = this.$refs.drop + const uploader = this.uploader.uploader + uploader.off('dragenter', this.onDragEnter) + uploader.off('dragleave', this.onDragLeave) + uploader.off('drop', this.onDrop) + uploader.unAssignDrop(dropEle) + } +} +</script> + +<style> +.uploader-drop { + position: relative; + padding: 10px; + overflow: hidden; + border: 1px dashed #ccc; + background-color: #f5f5f5; +} +.uploader-dragover { + border-color: #999; + background-color: #f7f7f7; +} +</style> diff --git a/src/components/subComponents/FileUpload/file.vue b/src/components/subComponents/FileUpload/file.vue new file mode 100644 index 0000000..43034f2 --- /dev/null +++ b/src/components/subComponents/FileUpload/file.vue @@ -0,0 +1,452 @@ +<template> + <div class="uploader-file" :status="status"> + <slot + :file="file" + :list="list" + :status="status" + :paused="paused" + :error="error" + :response="response" + :average-speed="averageSpeed" + :formated-average-speed="formatedAverageSpeed" + :current-speed="currentSpeed" + :is-complete="isComplete" + :is-uploading="isUploading" + :size="size" + :formated-size="formatedSize" + :uploaded-size="uploadedSize" + :progress="progress" + :progress-style="progressStyle" + :progressing-class="progressingClass" + :time-remaining="timeRemaining" + :formated-time-remaining="formatedTimeRemaining" + :type="type" + :extension="extension" + :file-category="fileCategory" + > + <div class="uploader-file-progress" :class="progressingClass" :style="progressStyle"></div> + <div class="uploader-file-info"> + <div class="uploader-file-name"> + <i class="uploader-file-icon" :icon="fileCategory"></i> + {{file.name}} + </div> + <div class="uploader-file-size">{{formatedSize}}</div> + <div class="uploader-file-meta"></div> + <div class="uploader-file-status"> + <span v-show="status !== 'uploading'">{{statusText}}</span> + <span v-show="status === 'uploading'"> + <!-- <span>{{progressStyle.progress}}</span> --> + <em>{{formatedAverageSpeed}}</em> + + <i> {{formatedTimeRemaining}}</i> + </span> + </div> + <div class="uploader-file-actions"> + <span class="uploader-file-pause" @click="pause"></span> + <span class="uploader-file-resume" @click="resume">锔�</span> + <span class="uploader-file-retry" @click="retry"></span> + <span class="uploader-file-remove" @click="remove"></span> + </div> + </div> + </slot> + </div> +</template> + +<script> +import Uploader from 'simple-uploader.js' +import events from './common/file-events' +import { secondsToStr } from './common/utils' + +const COMPONENT_NAME = 'uploader-file' + +export default { + name: COMPONENT_NAME, + props: { + file: { + type: Object, + default() { + return {} + } + }, + list: { + type: Boolean, + default: false + } + }, + data() { + return { + response: null, + paused: false, + error: false, + averageSpeed: 0, + currentSpeed: 0, + isComplete: false, + isUploading: false, + size: 0, + formatedSize: '', + uploadedSize: 0, + progress: 0, + timeRemaining: 0, + type: '', + extension: '', + progressingClass: '' + } + }, + computed: { + fileCategory() { + const extension = this.extension + const isFolder = this.file.isFolder + let type = isFolder ? 'folder' : 'unknown' + const categoryMap = this.file.uploader.opts.categoryMap + const typeMap = categoryMap || { + image: ['gif', 'jpg', 'jpeg', 'png', 'bmp', 'webp'], + video: ['mp4', 'm3u8', 'rmvb', 'avi', 'swf', '3gp', 'mkv', 'flv'], + audio: ['mp3', 'wav', 'wma', 'ogg', 'aac', 'flac'], + document: ['doc', 'txt', 'docx', 'pages', 'epub', 'pdf', 'numbers', 'csv', 'xls', 'xlsx', 'keynote', 'ppt', 'pptx'] + } + Object.keys(typeMap).forEach((_type) => { + const extensions = typeMap[_type] + if (extensions.indexOf(extension) > -1) { + type = _type + } + }) + return type + }, + progressStyle() { + const progress = Math.floor(this.progress * 100) + const style = `translateX(${Math.floor(progress - 100)}%)` + return { + progress: `${progress}%`, + webkitTransform: style, + mozTransform: style, + msTransform: style, + transform: style + } + }, + formatedAverageSpeed() { + return `${Uploader.utils.formatSize(this.averageSpeed)} / s` + }, + status() { + const isUploading = this.isUploading + const isComplete = this.isComplete + const isError = this.error + const paused = this.paused + if (isComplete) { + return 'success' + } else if (isError) { + return 'error' + } else if (isUploading) { + return 'uploading' + } else if (paused) { + return 'paused' + } else { + return 'waiting' + } + }, + statusText() { + const status = this.status + const fileStatusText = this.file.uploader.fileStatusText + let txt = status + if (typeof fileStatusText === 'function') { + txt = fileStatusText(status, this.response) + } else { + txt = fileStatusText[status] + } + return txt || status + }, + formatedTimeRemaining() { + const timeRemaining = this.timeRemaining + const file = this.file + if (timeRemaining === Number.POSITIVE_INFINITY || timeRemaining === 0) { + return '' + } + let parsedTimeRemaining = secondsToStr(timeRemaining) + const parseTimeRemaining = file.uploader.opts.parseTimeRemaining + if (parseTimeRemaining) { + parsedTimeRemaining = parseTimeRemaining(timeRemaining, parsedTimeRemaining) + } + return parsedTimeRemaining + } + }, + watch: { + status(newStatus, oldStatus) { + if (oldStatus && newStatus === 'uploading' && oldStatus !== 'uploading') { + this.tid = setTimeout(() => { + this.progressingClass = 'uploader-file-progressing' + }, 200) + } else { + clearTimeout(this.tid) + this.progressingClass = '' + } + } + }, + methods: { + _actionCheck() { + this.paused = this.file.paused + this.error = this.file.error + this.isUploading = this.file.isUploading() + }, + pause() { + this.file.pause() + this._actionCheck() + this._fileProgress() + }, + resume() { + this.file.resume() + this._actionCheck() + }, + remove() { + this.file.cancel() + }, + retry() { + this.file.retry() + this._actionCheck() + }, + processResponse(message) { + debugger + let res = message + try { + res = JSON.parse(message) + } catch (e) { } + this.response = res + }, + fileEventsHandler(event, args) { + const rootFile = args[0] + const file = args[1] + const target = this.list ? rootFile : file + if (this.file === target) { + if (this.list && event === 'fileSuccess') { + this.processResponse(args[2]) + return + } + this[`_${event}`].apply(this, args) + } + }, + _fileProgress() { + this.progress = this.file.progress() + this.averageSpeed = this.file.averageSpeed + this.currentSpeed = this.file.currentSpeed + this.timeRemaining = this.file.timeRemaining() + this.uploadedSize = this.file.sizeUploaded() + this._actionCheck() + }, + _fileSuccess(rootFile, file, message) { + if (rootFile) { + this.processResponse(message) + } + this._fileProgress() + this.error = false + this.isComplete = true + this.isUploading = false + console.log('rootFile, file, message',rootFile, file, message) + debugger + }, + _fileComplete() { + this._fileSuccess() + }, + _fileError(rootFile, file, message) { + this._fileProgress() + console.log('rootFile, file, message',rootFile, file, message) + debugger + this.processResponse(message) + this.error = true + this.isComplete = false + this.isUploading = false + } + }, + mounted() { + const staticProps = ['paused', 'error', 'averageSpeed', 'currentSpeed'] + const fnProps = [ + 'isComplete', + 'isUploading', + { + key: 'size', + fn: 'getSize' + }, + { + key: 'formatedSize', + fn: 'getFormatSize' + }, + { + key: 'uploadedSize', + fn: 'sizeUploaded' + }, + 'progress', + 'timeRemaining', + { + key: 'type', + fn: 'getType' + }, + { + key: 'extension', + fn: 'getExtension' + } + ] + staticProps.forEach(prop => { + this[prop] = this.file[prop] + }) + fnProps.forEach((fnProp) => { + if (typeof fnProp === 'string') { + this[fnProp] = this.file[fnProp]() + } else { + this[fnProp.key] = this.file[fnProp.fn]() + } + }) + + const handlers = this._handlers = {} + const eventHandler = (event) => { + handlers[event] = (...args) => { + this.fileEventsHandler(event, args) + } + return handlers[event] + } + events.forEach((event) => { + this.file.uploader.on(event, eventHandler(event)) + }) + }, + destroyed() { + events.forEach((event) => { + this.file.uploader.off(event, this._handlers[event]) + }) + this._handlers = null + } +} +</script> + +<style> +.uploader-file { + position: relative; + height: 49px; + line-height: 49px; + overflow: hidden; + border-bottom: 1px solid #cdcdcd; +} +.uploader-file[status="waiting"] .uploader-file-pause, +.uploader-file[status="uploading"] .uploader-file-pause { + display: block; +} +.uploader-file[status="paused"] .uploader-file-resume { + display: block; +} +.uploader-file[status="error"] .uploader-file-retry { + display: block; +} +.uploader-file[status="success"] .uploader-file-remove { + display: none; +} +.uploader-file[status="error"] .uploader-file-progress { + background: #ffe0e0; +} +.uploader-file-progress { + position: absolute; + width: 100%; + height: 100%; + background: #e2eeff; + transform: translateX(-100%); +} +.uploader-file-progressing { + transition: all 0.4s linear; +} +.uploader-file-info { + position: relative; + z-index: 1; + height: 100%; + overflow: hidden; +} +.uploader-file-info:hover { + background-color: rgba(240, 240, 240, 0.2); +} +.uploader-file-info i, +.uploader-file-info em { + font-style: normal; +} +.uploader-file-name, +.uploader-file-size, +.uploader-file-meta, +.uploader-file-status, +.uploader-file-actions { + float: left; + position: relative; + height: 100%; +} +.uploader-file-name { + width: 50%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + text-indent: 14px; + text-align: left; +} +.uploader-file-icon { + width: 24px; + height: 24px; + display: inline-block; + vertical-align: top; + margin-top: 13px; + margin-right: 8px; +} +.uploader-file-icon::before { + content: "馃搩"; + display: block; + height: 100%; + font-size: 24px; + line-height: 1; + text-indent: 0; +} +.uploader-file-icon[icon="folder"]::before { + content: "馃搨"; +} +.uploader-file-icon[icon="image"]::before { + content: "馃寙"; +} +.uploader-file-icon[icon="video"]::before { + content: "馃幀"; +} +.uploader-file-icon[icon="audio"]::before { + content: "馃幍"; +} +.uploader-file-icon[icon="document"]::before { + content: "馃搵"; +} +.uploader-file-size { + width: 11%; + text-indent: 10px; +} +.uploader-file-meta { + width: 8%; +} +.uploader-file-status { + width: 24%; + text-indent: 20px; +} +.uploader-file-actions { + width: 6%; +} +.uploader-file-actions > span { + display: none; + float: left; + width: 16px; + height: 16px; + margin-top: 16px; + margin-right: 10px; + cursor: pointer; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAABkCAYAAAD0ZHJ6AAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAJcEhZcwAACxMAAAsTAQCanBgAAARkSURBVGje7ZnfS1NRHMAH4ptPkvQSuAdBkCxD8FUQJMEULUgzy1KyyPVQ4JMiiP4Bvg6EwUQQfMmwhwRDshwaKUjDVCgoSdDNHkzTJZ6+Z37Purve8+PeTb2TM/ggu+ew89l33x8H9BBCPG7GowXTJej3+wnDvEm0JuLC04+EYWftVAUv+fiCvDUdQR1BHUEdQR3BTIygvixoQS14XgTtthLVdpNWwXRLqvQ724LplFRtyrYF0yVpFLQrKRVMh6RZ0I6kkmCqklaCqpKZH0FX56Crq9jVfdDVk0RfFrSgFsxkQVmLcdKCVrKySCrryhPEyYShhzOcrFtG0EoilfHHk1CRU5rF6ZjNZhlVOW6RnMSVyyilKies4pO41diVy8wIujoHXV3FGdMHXTtJKLFYTLhZtq4vC1rwXApCZTIqgR6g1PBMCO9DL3bMMSqBHqDU8EyISDAHiGKvWwcCQG2KgjlAFCDAOhAAap0K5gKLphk8mqJgLrCIgoxRJ4J5wKpJ7gAoMkn5EBXBPGDVJHcAFJmkfIhQcAql1oBpTvTol9gG9pm4RHAKpdaAaU706JfYBvaZuJVgPQrt4sFlnOh5MC/p3lmJYD0K7eLBZZzoeTAv6d5ZnuAYHjpgEOnk5F0ufhG6v1ggOIaHDhhEOjl5l4tfhO4vthLcwAMrFNvLJO5vEwhu4IEViu1lEve3WQmyoihQFBzG/V0CQVYUBYqCw7i/SxTBcpsRbFeIYLnNCLZbCY5b5KAnxRwct8hBj9McZFVMW0ihRNBuFdMWUigRlFaxuQ9WWYjRMTiIe5z0wSoLMToGB3GPsA9aTZIJoB+nRgBnM1tzOkkmgH6cGgGczWzNpzqLx3n/aULJJgezeNw07oxQySbVywKjBOgFRnDs+VEsx8FlgVEC9AIjOPb8KJYjvSzoG7UW1IJaUAtqQS14toLNM5fN5APdwBJA8G83Pk/aK/rgzVvXzeQD3cASQPBvNz5P2ssTzAaGUIrHEO6zI5gNDKEUjyHcxxWkh4Ylcowwk1QQpIeGJXKMMJO0EgwqyjGCioJBJvDrxRMSuVOTJEXfbz1/bHwWtBL0yoQehK6RucgE+bGzanzulQh6E3IgQV+xpc8kcrfuSO7eTfJ3ZYmQw0Oy9azVKOk1C/bJ5D5F38YPeLfx0rjWJxHsS0SqsSYuxySjj5qO5Oj7xQWy2VBtFOwzCy6ryH3YfE3uh64Y1xckgstJPydEjkkeHv07Iy4Xaao15+KCWTBx6M/db+T9xivSErqaJDdzXI6yLRE8Vgg0coex/SPJvT0SbWu0KpZtbgSpCH3NRt7I5OxHkObc6heU+/M/J5vrpBFM5GBLqCQux14COXs5CNXK5OjPGm1tSMrJSOMNYQ4mVTGV/L6zTL7+DovkbFUxbSW0Wo05l8hJWsU+cRWfSh+Mt5Lb1ck/J1TvVsdDaR/MiEni+llsdZuZp62EViu+96bpNjNPWwmtVnzvFd5m9IVVC54x/wA7gNvqFG9vXQAAAABJRU5ErkJggg==") + no-repeat 0 0; +} +.uploader-file-actions > span:hover { + background-position-x: -21px; +} +.uploader-file-actions .uploader-file-pause { + background-position-y: 0; +} +.uploader-file-actions .uploader-file-resume { + background-position-y: -17px; +} +.uploader-file-actions .uploader-file-retry { + background-position-y: -53px; +} +.uploader-file-actions .uploader-file-remove { + display: block; + background-position-y: -34px; +} +</style> diff --git a/src/components/subComponents/FileUpload/files.vue b/src/components/subComponents/FileUpload/files.vue new file mode 100644 index 0000000..1380ba9 --- /dev/null +++ b/src/components/subComponents/FileUpload/files.vue @@ -0,0 +1,42 @@ +<template> + <div class="uploader-files"> + <slot :files="files"> + <ul> + <li v-for="file in files" :key="file.id"> + <uploader-file :file="file"></uploader-file> + </li> + </ul> + </slot> + </div> +</template> + +<script> +import { uploaderMixin } from './common/mixins' +import UploaderFile from './file.vue' + +const COMPONENT_NAME = 'uploader-files' + +export default { + name: COMPONENT_NAME, + mixins: [uploaderMixin], + computed: { + files() { + return this.uploader.files + } + }, + components: { + UploaderFile + } +} +</script> + +<style> +.uploader-files { + position: relative; +} +.uploader-files > ul { + list-style: none; + margin: 0; + padding: 0; +} +</style> diff --git a/src/components/subComponents/FileUpload/index.vue b/src/components/subComponents/FileUpload/index.vue new file mode 100644 index 0000000..97c4562 --- /dev/null +++ b/src/components/subComponents/FileUpload/index.vue @@ -0,0 +1,230 @@ +<template> + <div class="file-uploader"> + <uploader + v-if="single" + ref="uploader" + :options="options" + :file-status-text="statusText" + class="uploader-single" + @file-added="onFileAdded" + @complete="onComplete" + > + <el-input :placeholder="uploadPlaceholder" size="small" :readonly="true" v-model="fileName"> + <uploader-btn slot="suffix" > + <el-tooltip :content="tipWords" placement="top" v-if="tip"> + <i class="el-icon-upload2" style="font-size:18px; color:#0088ff"></i> + </el-tooltip> + <i v-else class="el-icon-upload2" style="font-size:18px; color:#0088ff"></i> + </uploader-btn> + </el-input> + <uploader-list /> + </uploader> + + <uploader + v-else + ref="uploader" + :options="options" + :file-status-text="statusText" + class="uploader-example" + @file-added="onFileAdded" + @file-complete="fileComplete" + @complete="onComplete" + @close="closeHandle" + > + <uploader-btn ref="button"> + <i class="el-icon-upload2" style="font-size:18px; color:#0088ff"></i> + 涓婁紶 + </uploader-btn> + <uploader-list /> + </uploader> + </div> +</template> + +<script> +import uploader from "./uploader" +import SparkMD5 from 'spark-md5'; +import UploaderBtn from "./btn" +import UploaderList from "./list" + +export default { + components: { + uploader, + UploaderBtn, + UploaderList + }, + props: { + tip: { + type: Boolean, + default: false + }, + tipWords: { + type: String, + default: '' + }, + single: { + type: Boolean, + default: false + }, + uploadPlaceholder: { + type: String, + default: '' + }, + url: { + type: String, + default: "/data/api-f/file/upload" //"//192.168.20.10:3000/upload" + }, + }, + data() { + return { + fileName: "", + fileMd5: "", + attrs: { + accept: 'image/*' + }, + statusText: { + success: '涓婁紶鎴愬姛', + error: '涓婁紶澶辫触', + uploading: '涓婁紶涓�', + paused: '鏆傚仠涓�', + waiting: '绛夊緟涓�' + } + } + }, + computed: { + uploader() { + return this.$refs.uploader.uploader; + }, + options() { + return { + target: this.url, + testChunks: true, + headers: { + Authorization: sessionStorage.getItem('loginedInfo') && JSON.parse(sessionStorage.getItem('loginedInfo')).access_token + } + } + } + }, + methods: { + onFileAdded(file) { + if (this.single) { + this.uploader.fileList = this.uploader.fileList.slice([-1]); + this.$emit("file-added") + } + this.computeMD5(file); + }, + computeMD5(file) { + let fileReader = new FileReader(); + let time = new Date().getTime(); + let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; + let currentChunk = 0; + const chunkSize = 10 * 1024 * 1000; + let chunks = Math.ceil(file.size / chunkSize); + let spark = new SparkMD5.ArrayBuffer(); + // 鏂囦欢鐘舵�佽涓�"璁$畻MD5" + this.statusText.paused = "鍑嗗涓婁紶,姝e湪妫�鏌ユ枃浠�" + file.pause(); + loadNext(); + fileReader.onload = (e => { + spark.append(e.target.result); + if (currentChunk < chunks) { + currentChunk++; + loadNext(); + } else { + let md5 = spark.end(); + this.computeMD5Success(md5, file); + this.fileName = file.name; + this.fileMd5 = md5; + // console.log(`MD5璁$畻瀹屾瘯锛�${file.name} \nMD5锛�${md5} \n鍒嗙墖锛�${chunks} 澶у皬:${file.size} 鐢ㄦ椂锛�${new Date().getTime() - time} ms`); + } + }); + fileReader.onerror = function () { + this.error(`鏂囦欢${file.name}璇诲彇鍑洪敊锛岃妫�鏌ヨ鏂囦欢`) + file.cancel(); + }; + function loadNext() { + let start = currentChunk * chunkSize; + let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize; + fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end)); + } + }, + computeMD5Success(md5, file) { + // 灏嗚嚜瀹氫箟鍙傛暟鐩存帴鍔犺浇uploader瀹炰緥鐨刼pts涓� + if (this.$route.path.indexOf("VideoManage") >= 0) { + Object.assign(this.uploader.opts, { + query: { + stackId: this.DataStackPool.selectedDir.id + // ...this.params, + } + }) + } + file.uniqueIdentifier = md5; + file.resume(); + this.statusText.paused = "鏆傚仠涓�"; + }, + onComplete() { + debugger + this.$emit("complete", { filename: this.fileName, identifier: this.fileMd5 }); + }, + fileComplete() { + // console.log('file complete', arguments) + }, + closeHandle() { + this.$emit("close") + } + }, + mounted() { + this.$nextTick(() => { + window.uploader = this.$refs.uploader.uploader + }) + } +} +</script> + +<style lang="scss"> +.file-uploader { + .el-input__suffix,.el-input__suffix-inner{ + outline: none!important; + } + .el-tooltip.focusing{ + outline: none; + } + .uploader-example { + width: 99%; + // padding: 15px; + // margin: 40px auto 0; + font-size: 12px; + // box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); + background-color: #fff; + } + .uploader-example .uploader-btn { + position: relative; + display: none; + // float: right; + // top: -45px; + } + .uploader-example .uploader-list { + max-height: 440px; + overflow: auto; + overflow-x: hidden; + overflow-y: auto; + } + .uploader-single { + position: unset; + .close { + display: none; + } + .uploader-btn { + border: 0px; + } + .uploader-file { + height: 2px; + .uploader-file-progress { + background: #3d68e1; + } + .uploader-file-info { + display: none; + } + } + } +} +</style>> diff --git a/src/components/subComponents/FileUpload/list.vue b/src/components/subComponents/FileUpload/list.vue new file mode 100644 index 0000000..b572727 --- /dev/null +++ b/src/components/subComponents/FileUpload/list.vue @@ -0,0 +1,42 @@ +<template> + <div class="uploader-list"> + <slot :file-list="fileList"> + <ul> + <li v-for="file in fileList" :key="file.id"> + <uploader-file :file="file" :list="true"></uploader-file> + </li> + </ul> + </slot> + </div> +</template> + +<script> +import { uploaderMixin } from './common/mixins' +import UploaderFile from './file.vue' + +const COMPONENT_NAME = 'uploader-list' + +export default { + name: COMPONENT_NAME, + mixins: [uploaderMixin], + computed: { + fileList() { + return this.uploader.fileList + } + }, + components: { + UploaderFile + } +} +</script> + +<style> +.uploader-list { + position: relative; +} +.uploader-list > ul { + list-style: none; + margin: 0; + padding: 0; +} +</style> diff --git a/src/components/subComponents/FileUpload/unsupport.vue b/src/components/subComponents/FileUpload/unsupport.vue new file mode 100644 index 0000000..59626ee --- /dev/null +++ b/src/components/subComponents/FileUpload/unsupport.vue @@ -0,0 +1,30 @@ +<template> + <div class="uploader-unsupport" v-show="!support"> + <slot> + <p> + Your browser, unfortunately, is not supported by Uploader.js. The library requires support for + <a href="http://www.w3.org/TR/FileAPI/">the HTML5 File API</a> along with + <a href="http://www.w3.org/TR/FileAPI/#normalization-of-params">file slicing</a>. + </p> + </slot> + </div> +</template> + +<script> +import { uploaderMixin, supportMixin } from './common/mixins' + +const COMPONENT_NAME = 'uploader-unsupport' + +export default { + name: COMPONENT_NAME, + mixins: [uploaderMixin, supportMixin] +} +</script> + +<style> +.uploader-unsupport { + position: relative; + z-index: 10; + overflow: hidden; +} +</style> diff --git a/src/components/subComponents/FileUpload/uploader.vue b/src/components/subComponents/FileUpload/uploader.vue new file mode 100644 index 0000000..2df8221 --- /dev/null +++ b/src/components/subComponents/FileUpload/uploader.vue @@ -0,0 +1,155 @@ +<template> + <div class="uploader"> + <!-- <div class="close" @click="closeHandle">x</div> --> + <slot :files="files" :file-list="fileList" :started="started"> + <uploader-unsupport></uploader-unsupport> + <uploader-drop> + <!-- <p>鎷栧姩鏂囦欢鍒拌鍖哄煙涓婁紶</p> --> + <uploader-btn>閫夋嫨鏂囦欢</uploader-btn> + <uploader-btn :directory="true">閫夋嫨鏂囦欢澶�</uploader-btn> + </uploader-drop> + <uploader-list></uploader-list> + </slot> + </div> +</template> + +<script> +import Uploader from 'simple-uploader.js' +import { kebabCase } from './common/utils' +import UploaderBtn from './btn.vue' +import UploaderDrop from './drop.vue' +import UploaderUnsupport from './unsupport.vue' +import UploaderList from './list.vue' + +const COMPONENT_NAME = 'uploader' +const FILE_ADDED_EVENT = 'fileAdded' +const FILES_ADDED_EVENT = 'filesAdded' +const UPLOAD_START_EVENT = 'uploadStart' + +export default { + name: COMPONENT_NAME, + provide() { + return { + uploader: this + } + }, + props: { + options: { + type: Object, + default() { + return {} + } + }, + autoStart: { + type: Boolean, + default: true + }, + fileStatusText: { + type: [Object, Function], + default() { + return { + success: 'success', + error: 'error', + uploading: 'uploading', + paused: 'paused', + waiting: 'waiting' + } + } + } + }, + data() { + return { + started: false, + files: [], + fileList: [] + } + }, + methods: { + uploadStart() { + this.started = true + }, + fileAdded(file) { + this.$emit(kebabCase(FILE_ADDED_EVENT), file) + if (file.ignored) { + // is ignored, filter it + return false + } + }, + filesAdded(files, fileList) { + this.$emit(kebabCase(FILES_ADDED_EVENT), files, fileList) + if (files.ignored || fileList.ignored) { + // is ignored, filter it + return false + } + }, + fileRemoved(file) { + this.files = this.uploader.files + this.fileList = this.uploader.fileList + }, + filesSubmitted(files, fileList) { + this.files = this.uploader.files + this.fileList = this.uploader.fileList + if (this.autoStart) { + this.uploader.upload() + } + }, + allEvent(...args) { + const name = args[0] + const EVENTSMAP = { + [FILE_ADDED_EVENT]: true, + [FILES_ADDED_EVENT]: true, + [UPLOAD_START_EVENT]: 'uploadStart' + } + const handler = EVENTSMAP[name] + if (handler) { + if (handler === true) { + return + } + this[handler].apply(this, args.slice(1)) + } + args[0] = kebabCase(name) + this.$emit.apply(this, args) + }, + closeHandle() { + this.$emit("close") + } + }, + created() { + this.options.initialPaused = !this.autoStart + const uploader = new Uploader(this.options) + this.uploader = uploader + this.uploader.fileStatusText = this.fileStatusText + uploader.on('catchAll', this.allEvent) + uploader.on(FILE_ADDED_EVENT, this.fileAdded) + uploader.on(FILES_ADDED_EVENT, this.filesAdded) + uploader.on('fileRemoved', this.fileRemoved) + uploader.on('filesSubmitted', this.filesSubmitted) + }, + destroyed() { + const uploader = this.uploader + uploader.off('catchAll', this.allEvent) + uploader.off(FILE_ADDED_EVENT, this.fileAdded) + uploader.off(FILES_ADDED_EVENT, this.filesAdded) + uploader.off('fileRemoved', this.fileRemoved) + uploader.off('filesSubmitted', this.filesSubmitted) + this.uploader = null + }, + components: { + UploaderBtn, + UploaderDrop, + UploaderUnsupport, + UploaderList + } +} +</script> + +<style lang="scss"> +.uploader { + .close { + position: absolute; + right: 5px; + top: 3px; + cursor: pointer; + } +} +</style> diff --git a/src/components/subComponents/IPInput.vue b/src/components/subComponents/IPInput.vue new file mode 100644 index 0000000..4f59322 --- /dev/null +++ b/src/components/subComponents/IPInput.vue @@ -0,0 +1,231 @@ +<template> + <div class="ip-input-container"> + <div class="ip-segment" v-for="(segment, index) in segments" :key="index"> + <input + type="text" + maxlength="3" + class="ip-segment-input" + :value="segment" + :placeholder="placeholder" + :disabled="disabled" + v-on:keydown="onInputKeydown($event, index)" + v-on:input="onInput($event, index)" + v-on:blur="onInputBlur()" + v-on:paste="onPaste($event, index)" + /> + <i v-show="index != segments.length - 1">.</i> + </div> + </div> +</template> + +<script> +/* global document*/ +/** + * get the cursor position of the element + * @param {Element} el the element + * @return {Integer} the position fo the cursor + */ +function getRange(el) { + var cuRange; + var tbRange; + var headRange; + var range; + var dupRange; + var ret = {}; + if (el.setSelectionRange) { + // standard + ret.begin = el.selectionStart; + ret.end = el.selectionEnd; + ret.result = el.value.substring(ret.begin, ret.end); + } else if (document.selection) { + // ie + if (el.tagName.toLowerCase() === "input") { + cuRange = document.selection.createRange(); + tbRange = el.createTextRange(); + tbRange.collapse(true); + tbRange.select(); + headRange = document.selection.createRange(); + headRange.setEndPoint("EndToEnd", cuRange); + ret.begin = headRange.text.length - cuRange.text.length; + ret.end = headRange.text.length; + ret.result = cuRange.text; + cuRange.select(); + } else if (el.tagName.toLowerCase() === "textarea") { + range = document.selection.createRange(); + dupRange = range.duplicate(); + dupRange.moveToElementText(el); + dupRange.setEndPoint("EndToEnd", range); + ret.begin = dupRange.text.length - range.text.length; + ret.end = dupRange.text.length; + ret.result = range.text; + } + } + el.focus(); + return ret; +} +export default { + props: { + ip: { + type: String, + defalut: "" + }, + item: {}, + placeholder: String, + onChange: Function, + onBlur: Function, + onItemChange: Function, + disabled: { + type: Boolean, + default: false + } + }, + data() { + return { + segments: ["", "", "", ""] + }; + }, + watch: { + ip(ip) { + this.syncIp(ip); + } + }, + methods: { + onInputKeydown(event, index) { + var keyCode = event.keyCode || event.which; + var value = event.target.value; + if (keyCode === 8 || keyCode === 37) { + // move the cursor to previous input if backspace and left arrow is pressed at the begin of one input + if ( + (value.length === 0 || getRange(event.target).end === 0) && + index > 0 + ) { + this.$el.getElementsByTagName("input")[index - 1].focus(); + // When jump to pre input(enter "backspace"), thr cursor should in the end. + // before fix: 127.|0.0.0 => 12|7.0.0.1 + // after fix: 127.|0.0.0 = > 127|.0.0.0 + // notes: "|" mean the cursor position. + event.preventDefault(); + } + } else if (keyCode === 39 && keyCode === 110) { + if (getRange(event.target).end === value.length && index < 3) { + // move to cursor to the next input if right arrow is pressed at the end of one input + this.$el.getElementsByTagName("input")[index + 1].focus(); + } + } + }, + onInput(event, index) { + var value = event.target.value; + event.target.value = this.segments[index]; + var segment = Number(value); + if (isNaN(segment)) { + return; + } else if (value === "") { + this.segments.splice(index, 1, ""); + } else if (segment > 255 || segment < 0) { + // set the segment to 255 if out of ip range + this.segments.splice(index, 1, 255); + } else { + this.segments.splice(index, 1, segment); + } + // jump to next input + if ( + (value.length === 3 && index < 3) || + value[value.length - 1] === "." + ) { + this.$el.getElementsByTagName("input")[index + 1].focus(); + } + }, + onInputBlur() { + setTimeout(() => { + this.$emit("on-blur", this.segments.join(".")); + if (this.onBlur) { + this.onBlur(this.segments.join(".")); + } + if (this.onItemChange) { + this.onItemChange(this.segments.join("."), this.item) + } + }, 50); + }, + onPaste(e, index) { + var pasteText = e.clipboardData.getData("text/plain"); + var segments = pasteText.split("."); + segments.forEach((segment, i) => { + if ( + index + i < 4 && + !isNaN(segment) && + segment >= 0 && + segment <= 255 + ) { + this.segments.splice(index + i, 1, segment); + } + }); + e.preventDefault(); + }, + syncIp(ip) { + if (ip && ip.indexOf(".") !== -1) { + ip.split(".").map((segment, index) => { + if (isNaN(segment) || segment < 0 || segment > 255) { + segment = 255; + } + this.segments.splice(index, 1, segment); + return segment; + }); + } + } + }, + mounted() { + this.syncIp(this.ip); + this.$watch( + () => { + return this.segments.join("."); + }, + (val, oldValue) => { + if (val !== oldValue) { + if (val === "...") { + val = ""; + } + if (this.onChange) { + this.onChange(val); + } + } + } + ); + } +}; +</script> + +<style lang="scss" scoped> +.ip-input-container { + display: inline-block; + width: 100%; + height: 32px; + line-height: normal; + border: 1px solid #dcdfe6; + box-sizing: border-box; + background-color: #fff; + text-align: left; + max-width: 360px; +} +.ip-segment { + display: inline-block; + width: 25%; + height: 32px; + line-height: normal; + input { + width: 90%; + height: 32px; + line-height: normal; + border: none; + outline: none; + text-align: center; + text-indent: 0px; + margin: 0px; + padding: 0px; + background-color: transparent; + } + i { + display: inline-block; + font-size: 18px; + } +} +</style> \ No newline at end of file diff --git a/src/components/subComponents/LocalVedioCard.vue b/src/components/subComponents/LocalVedioCard.vue new file mode 100644 index 0000000..a1c5bd1 --- /dev/null +++ b/src/components/subComponents/LocalVedioCard.vue @@ -0,0 +1,139 @@ +<template> + <div class="board-card flex-center"> + <div style="width:40%;"> + <div class="top-text"> + <em>{{title}}</em> + </div> + <div class="mid-text"> + <em>{{total}}</em> + </div> + </div> + <div style="height:86px;"> + <el-divider class="divider-css" direction="vertical"></el-divider> + </div> + <div style="width:59%;height:100%;" class="flex-center"> + <div class="out-div-33"> + <div class="txt-css"> + <span>瑙嗛</span> + </div> + <el-tooltip v-if="total" effect="dark" placement="top" content="蹇欑"> + <div class="icon-css"> + <i class="iconfont iconmanglu"></i> + </div> + </el-tooltip> + <el-tooltip v-else effect="dark" placement="top" content="绛夊緟"> + <div class="icon-css"> + <i class="iconfont icondengdai1"></i> + </div> + </el-tooltip> + </div> + <div style="height:86px;"> + <el-divider class="divider-css" direction="vertical"></el-divider> + </div> + <div class="out-div-33"> + <div class="txt-css"> + <span>鍥剧墖</span> + </div> + <el-tooltip effect="dark" placement="top" content="绛夊緟"> + <div class="icon-css"> + <i class="iconfont icondengdai1"></i> + </div> + </el-tooltip> + </div> + <div style="height:86px;"> + <el-divider class="divider-css" direction="vertical"></el-divider> + </div> + <div class="out-div-33"> + <div class="txt-css"> + <span>闊抽</span> + </div> + <el-tooltip effect="dark" placement="top" content="绛夊緟"> + <div class="icon-css"> + <i class="iconfont icondengdai1"></i> + </div> + </el-tooltip> + </div> + </div> + </div> +</template> + +<script> +export default { + name: "BoardCard", + props: { + title: { type: String, default: "" }, + total: { type: String, default: "" }, + success: { type: String, default: "" }, + warning: { type: String, default: "" } + } +} +</script> +<style lang="scss"> +.board-card { + height: 120px; + width: 100%; + display: inline-block; + margin: 10px; + background: #ffffff; + border: 1px solid #e2e2e2; + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + border-radius: 4px; + cursor: pointer; + .top-text { + line-height: 30px; + font-family: PingFangSC-Medium; + font-size: 14px; + color: #222222; + } + .mid-text { + margin-bottom: 18px; + font-family: PingFangSC-Medium; + font-size: 18px; + color: #ff7733; + } + .bottom-text { + position: relative; + top: 3px; + left: 1px; + color: #666666; + font-size: 13px; + } + em { + font-weight: 700; + } + hr { + background: rgb(226, 226, 226); + border: 0; + height: 1px; + } + i { + font-size: 20px; + } + .divider-css{ + height: 100%; + margin: 0; + } + .el-divider--horizontal { + display: block; + height: 1px; + width: 100%; + margin: 3px 0; + } + .out-div-33{ + width: 33%; + height: 100%; + .txt-css{ + width: 100%; + height: 50%; + position: relative; + top: 30px; + } + .icon-css{ + width: 100%; + height: 30%; + margin-top: 10px; + position: relative; + } + } +} +</style> \ No newline at end of file diff --git a/src/components/subComponents/LocalVedioList.vue b/src/components/subComponents/LocalVedioList.vue new file mode 100644 index 0000000..511f87c --- /dev/null +++ b/src/components/subComponents/LocalVedioList.vue @@ -0,0 +1,129 @@ +<template> + <div id="realTimeList" class="out-div-rt"> + <div class="top-menu"> + <span class="iconfont iconku" style="font-size:20px;"></span> + <span style="font-size:14px; margin-left: 5px;font-weight: 600;">鏁版嵁鏍�</span> + </div> + <ul> + <li + v-for="(item,index) in DataStackPool.dirs" + :key="index" + @click="handleClick(item)" + :class="DataStackPool.selectedDir.id == item.id ? 'bg' : ''" + > + <!-- 鏂囦欢澶瑰浘鏍� --> + <span class="iconfont iconshipinwenjianjia-new folder" v-if="item.type === 1"></span> + <span class="iconfont icontupianwenjianjia-copy folder" v-else-if="item.type === 2"></span> + <span class="iconfont iconshipinwenjianjia1 folder" v-else-if="item.type === 3"></span> + <span class="iconfont iconwenjian folder" v-else></span> + + <span class="folder-name">{{item.name}}</span> + + <!-- 绠楁硶閰嶇疆涓嶅叏 --> + <i class="iconfont iconicon-test6 folder-status" v-if="item.status === 0"></i> + <!-- 姝e湪澶勭悊 --> + <i class="iconfont iconicon-test11 folder-status" v-else-if="item.status === 2"></i> + <!-- 绛夊緟澶勭悊 --> + <i class="iconfont iconicon-test5 folder-status" v-else-if="item.status === 1"></i> + <!-- 鏈煡鍘熷洜 --> + <i class="iconfont iconicon-test5 folder-status" v-else></i> + <!-- <i class="iconfont iconicon-test11 folder-status"></i> --> + <el-switch + size="mini" + style="float:right; margin:2px 5px;" + v-model="item.enable" + @change="switchEnable(item)" + ></el-switch> + </li> + </ul> + </div> +</template> +<script> +import { switchDir } from "@/api/localVedio" + +export default { + name: 'localVedioList', + props: { + isMutl: { + type: Boolean, + default: true + } + }, + data() { + return { + list: [], + checkedVedio: [], + isShow: true, + dateMill: new Date(), + showCheckBox: false, + } + }, + methods: { + handleClick(item) { + this.DataStackPool.selectedDir = item; + }, + switchEnable(item) { + switchDir({ enable: item.enable, id: item.id }).then(rsp => { + console.log(rsp) + }) + } + } +} +</script> +<style lang="scss"> +.out-div-rt { + width: 100%; + height: 100%; + .top-menu { + text-align: left; + } + + .folder { + color: #3d68e1; + font-size: 20px; + float: left; + line-height: 25px; + } + .folder-name { + font-size: 14px; + margin-left: 5px; + float: left; + line-height: 27px; + } + .folder-status { + color: #3d68e1; + font-size: 18px; + float: right; + line-height: 25px; + } + + ul { + margin: 10px 25px; + } + li { + width: 100%; + height: 25px; + margin-top: 2px; + cursor: pointer; + .el-switch__core { + width: 27px !important; + height: 14px; + } + .el-switch__core:after { + width: 10px; + height: 10px; + } + .el-switch.is-checked .el-switch__core::after { + left: 100%; + margin-left: -11px; + } + } +} + +.bg { + background: #e1e1e1; +} +.clickStatus { + background: #e1e1e1; +} +</style> diff --git a/src/components/subComponents/ModelCard.vue b/src/components/subComponents/ModelCard.vue new file mode 100644 index 0000000..febadaf --- /dev/null +++ b/src/components/subComponents/ModelCard.vue @@ -0,0 +1,583 @@ +<template> + <div class="model-card-box" :style="`height:${height};width:${width};`"> + <el-tabs style="height: 100%;" @before-leave="changeTabs" v-model="VideoPhotoData.activeName"> + <el-tab-pane label="澶у浘" name="pic"> + <div + class="model-card-box-left" + :style="data.targetInfo !== null && data.targetInfo[0].picSmUrl !== '' + ? 'width: 65%;padding: 5px;box-sizing: border-box' + : 'width: 100%;padding: 5px;box-sizing: border-box'" + > + <div class="img-box"> + <p class="img-box-title"> + <b>鍏ㄦ櫙鍥�</b> + </p> + <img-down + v-if="data.targetInfo !== null && data.targetInfo[0].picSmUrl !== ''" + :url="data.picMaxUrl[0]" + ></img-down> + <!-- 浜鸿劯绫诲瀷 --> + <img-down + v-else-if="(data.targetInfo == null || data.targetInfo[0].picSmUrl == '') && data.picMaxUrl.length == 1" + :url="data.picMaxUrl[0]" + ></img-down> + <!-- 鏅�歽olo绫� --> + <el-carousel + v-else-if="(data.targetInfo == null || data.targetInfo[0].picSmUrl == '') && data.picMaxUrl.length > 1" + trigger="click" + height="100%" + :autoplay="false" + > + <el-carousel-item v-for="(item, index) in data.picMaxUrl" :key="index"> + <img-down :url="item"></img-down> + </el-carousel-item> + </el-carousel> + <!-- 鎸佺画鏃堕棿yolo绫� --> + <div + class="describe" + v-if="data.targetInfo == null || data.targetInfo[0].picSmUrl == ''" + > + <p> + <span class="fontStyleForModel">{{ data.picDate }}</span> + </p> + <p> + <span class="fontStyleForModel">{{ data.cameraAddr }}</span> + </p> + <p style="width:100%"> + <span v-for="(item,index) in data.alarmRules" :key="index+'rule'"> + <span class="fontStyleForModel">{{data.taskName}}</span> + <span + v-if="item.alarmLevel !== '鎾ら槻'" + class="fontStyleForModel" + >{{item.alarmLevel}}</span> + <span v-if="item.isLink" class="fontStyleForModel">鑱斿姩浠诲姟</span> + <span v-if="index < data.alarmRules.length-1">/ </span> + </span> + </p> + </div> + <!-- yolo绫诲ぇ鍥� --> + <div class="describeBigImage" v-else> + <p> + <span class="fontStyleForModel">{{ data.picDate }}</span> + </p> + <p> + <span class="fontStyleForModel">{{ data.cameraAddr }}</span> + </p> + <p style="width:100%"> + <span v-for="(item,index) in data.alarmRules" :key="index+'rule'"> + <span class="fontStyleForModel">{{data.taskName}}</span> + <span + v-if="item.alarmLevel !== '鎾ら槻'" + class="fontStyleForModel" + >{{item.alarmLevel}}</span> + <span v-if="item.isLink" class="fontStyleForModel">鑱斿姩浠诲姟</span> + <span v-if="index < data.alarmRules.length-1">/ </span> + </span> + </p> + <p style="width:100%"> + <span class="fontStyleForModel">{{data.showLabels}}</span> + </p> + </div> + <!-- 浜鸿劯绫诲ぇ鍥� --> + </div> + </div> + <div + v-if="data.targetInfo && data.targetInfo !== null && data.targetInfo[0].picSmUrl !== ''" + class="model-card-box-right" + :style="data.targetInfo && data.targetInfo !== null && data.targetInfo[0].picSmUrl !== '' + ? 'width: 35%;box-sizing: border-box;' + : ''" + > + <p class="img-box-title"> + <b>鎶撴媿鍥�</b> + </p> + <!-- 宸﹀彸涓ゅ紶鐨勪汉鑴稿姣旀ā寮� --> + <div class="img-box" v-if="data.baseInfo && data.baseInfo.length >= 1" ref="picSmBox"> + <div class="card-img-box-compear-left"> + <!-- <img :src="'/httpImage/'+data.targetInfo[0].picSmUrl" ref="picSm" /> --> + <img-down :url="data.targetInfo[0].picSmUrl" :isPreview="false"></img-down> + </div> + <el-carousel + @change="changeInitialIndex" + :initial-index="initialIndex" + :autoplay="false" + indicator-position="none" + :arrow="data.baseInfo.length > 1 ? 'always' : 'never'" + v-if="data.baseInfo[0].targetPicUrl != ''" + class="card-img-box-compear-right" + > + <el-carousel-item v-for="(item, index) in data.baseInfo" :key="index"> + <!-- <img :src="'/httpImage/'+item.targetPicUrl" /> --> + <img-down :url="item.targetPicUrl" :isPreview="false"></img-down> + </el-carousel-item> + </el-carousel> + <div + class="img-compareScore" + v-if="data.baseInfo[0].targetPicUrl != ''" + :style=" + data.baseInfo[initialIndex].bwType === '1' + ? `background: red;` + : `background: green;` + " + > + <b>{{ data.baseInfo[initialIndex].compareScore | percentage }}</b> + </div> + </div> + <!-- 娌℃湁姣斿鐨勪汉鑴歌瘑鍒ā寮� --> + <div class="img-box" v-if="!data.baseInfo && data.targetInfo[0].picSmUrl !== '' "> + <div class="card-img-box-compear-left" style="width:60%;margin-top:5px"> + <!-- <img :src="'/httpImage/'+data.targetInfo[0].picSmUrl" /> --> + <img-down :url="data.targetInfo[0].picSmUrl" :isPreview="false"></img-down> + </div> + </div> + <div class="baseInfo" v-if="data.baseInfo && data.baseInfo[0].targetPicUrl != ''"> + <div class="baseInfo_left"> + <p> + <span class="labelInfo">搴曞簱</span> + </p> + <p> + <span class="labelInfo">濮撳悕</span> + </p> + <p> + <span class="labelInfo">鎬у埆</span> + </p> + <p> + <span class="labelInfo">韬唤璇佸彿</span> + </p> + <p> + <span class="labelInfo">鎵嬫満鍙�</span> + </p> + <p> + <span class="labelInfo">浜哄憳绛夌骇</span> + </p> + </div> + <div class="baseInfo_right"> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].tableName" + >{{ data.baseInfo[initialIndex].tableName }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].targetName" + >{{ data.baseInfo[initialIndex].targetName }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].labels.split('/')[1]" + >{{ data.baseInfo[initialIndex].labels.split("/")[1] }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].labels.split('/')[2]" + >{{ data.baseInfo[initialIndex].labels.split("/")[2] }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].labels.split('/')[0]" + >{{ data.baseInfo[initialIndex].labels.split("/")[0] }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].monitorLevel" + >{{ data.baseInfo[initialIndex].monitorLevel }}</span> + </p> + </div> + </div> + </div> + </el-tab-pane> + <el-tab-pane label="瑙嗛" name="video" class="video-tabs"> + <div + class="model-card-box-left" + :style="data.targetInfo !== null && data.targetInfo[0].picSmUrl !== '' + ? 'width: 65%;padding: 5px;box-sizing: border-box' + : 'width: 70%;padding: 5px;box-sizing: border-box;margin-left:15%'" + > + <div class="img-box"> + <video + :src="'/httpImage/' + data.videoUrl" + controls + style="margin-top: 12px;" + >鎮ㄧ殑娴忚鍣ㄤ笉鏀寔 video 鏍囩銆�</video> + </div> + <!-- <div class="merge"> + <el-button type="primary" @click="mergeVideo">鍚堝苟瑙嗛</el-button> + <a name="download" @click="downloadfile">涓嬭浇</a> + <a href="/httpImage/192.168.20.112:6081/31,02c86c199cd9b1" download="panlei.mp4">涓嬭浇2</a> + </div>--> + </div> + <div + v-if="data.targetInfo !== null && data.targetInfo[0].picSmUrl !== ''" + class="model-card-box-right" + :style="data.targetInfo !== null && data.targetInfo[0].picSmUrl !== '' + ? 'width: 35%;box-sizing: border-box;' + : ''" + > + <p class="img-box-title"> + <b>鎶撴媿鍥�</b> + </p> + <!-- 宸﹀彸涓ゅ紶鐨勪汉鑴稿姣旀ā寮� --> + <div class="img-box" v-if="data.baseInfo && data.baseInfo.length >= 1" ref="picSmBox"> + <div class="card-img-box-compear-left"> + <img-down :url="data.targetInfo[0].picSmUrl" :isPreview="false"></img-down> + </div> + <el-carousel + @change="changeInitialIndex" + :initial-index="initialIndex" + :autoplay="false" + indicator-position="none" + v-if="data.baseInfo[0].targetPicUrl != ''" + class="card-img-box-compear-right" + :arrow="data.baseInfo.length > 1 ? 'always' : 'never'" + > + <el-carousel-item v-for="(item, index) in data.baseInfo" :key="index"> + <!-- <img :src="'/httpImage/'+item.targetPicUrl" /> --> + <img-down :url="item.targetPicUrl" :isPreview="false"></img-down> + </el-carousel-item> + </el-carousel> + <div + class="img-compareScore" + v-if="data.baseInfo[0].targetPicUrl != ''" + :style=" + data.baseInfo[initialIndex].bwType === '1' + ? `background: red;` + : `background: green;` + " + > + <b>{{ data.baseInfo[initialIndex].compareScore | percentage }}</b> + </div> + </div> + <!-- 娌℃湁姣斿鐨勪汉鑴歌瘑鍒ā寮� --> + <div class="img-box" v-if="!data.baseInfo && data.picMaxUrl "> + <div class="card-img-box-compear-left" style="width:60%;margin-top:5px"> + <!-- <img :src="'/httpImage/'+data.targetInfo[0].picSmUrl" /> --> + <img-down :url="data.targetInfo[0].picSmUrl" :isPreview="false"></img-down> + </div> + </div> + <div class="baseInfo" v-if="data.baseInfo && data.baseInfo[0].targetPicUrl != ''"> + <div class="baseInfo_left"> + <p> + <span class="labelInfo">搴曞簱</span> + </p> + <p> + <span class="labelInfo">濮撳悕</span> + </p> + <p> + <span class="labelInfo">鎬у埆</span> + </p> + <p> + <span class="labelInfo">韬唤璇佸彿</span> + </p> + <p> + <span class="labelInfo">鎵嬫満鍙�</span> + </p> + <p> + <span class="labelInfo">浜哄憳绛夌骇</span> + </p> + </div> + <div class="baseInfo_right"> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].tableName" + >{{ data.baseInfo[initialIndex].tableName }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].targetName" + >{{ data.baseInfo[initialIndex].targetName }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].labels.split('/')[1]" + >{{ data.baseInfo[initialIndex].labels.split("/")[1] }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].labels.split('/')[2]" + >{{ data.baseInfo[initialIndex].labels.split("/")[2] }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].labels.split('/')[0]" + >{{ data.baseInfo[initialIndex].labels.split("/")[0] }}</span> + </p> + <p class="valueInfo"> + <span + :title="data.baseInfo[initialIndex].monitorLevel" + >{{ data.baseInfo[initialIndex].monitorLevel }}</span> + </p> + </div> + </div> + </div> + </el-tab-pane> + </el-tabs> + </div> +</template> +<script> +/* eslint-disable */ +import CameraPlayer from "@/components/player"; +import imgDown from "@/components/subComponents/imgDown" +export default { + components: { + CameraPlayer, + imgDown + }, + props: { + height: { + type: String, + default: "100%" + }, + width: { + type: String, + default: "100%" + }, + data: "" + }, + filters: { + percentage(score) { + return score.toFixed(2) + "%" + } + }, + mounted() { + this.VideoPhotoData.activeName = "pic" + }, + data() { + return { + initialIndex: 0, + }; + }, + methods: { + changeTabs(activeName, oldActiveName) { + console.log(activeName, oldActiveName); + }, + changeInitialIndex(index) { + this.initialIndex = index; + }, + downloadfile() { + this.filecontent = "this is my file content"; + let a = document.createElement('a'); + + a.href = "data:text/json;charset=utf-8," + this.filecontent; + // a.url = "http://192.168.20.112:6154/93,02c5aea4fc614e"; + a.download = "video.mp4"; + a.click(); + } + }, +}; +</script> +<style lang="scss"> +.fontStyleForModel { + font-family: PingFangSC-Medium; + font-size: 14px; + color: #222222; + font-weight: 600; + letter-spacing: 0.28px; +} +.model-card-box { + box-sizing: border-box; + padding: 5px; + .el-tabs { + .el-tabs__item { + font-size: 16px !important; + } + } + .el-tabs__content { + height: calc(100% - 55px); + .el-tab-pane { + height: 100%; + } + .model-card-box-left, + .model-card-box-right { + height: 100%; + float: left; + .baseInfo { + margin-top: 5px; + text-align: left; + .baseInfo_left { + float: left; + width: 30%; + text-align: left; + font-family: PingFangSC-Regular; + font-size: 12px; + color: #999999; + letter-spacing: 0.28px; + } + .baseInfo_right { + float: left; + width: 70%; + text-align: left; + font-family: PingFangSC-Regular; + font-size: 12px; + color: #101010; + letter-spacing: 0.28px; + line-height: 20px; + .valueInfo { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 130px; + } + } + p { + line-height: 20px; + } + } + } + .model-card-box-left { + width: 60%; + .img-box { + .el-carousel__arrow { + bottom: inherit !important; + top: 50% !important; + } + .el-carousel__arrow--right { + right: 10px !important; + } + .el-carousel__arrow--left { + left: 10px !important; + } + .img-box-title { + text-align: left; + } + height: calc(100% - 100px); + .el-carousel { + width: 100%; + height: 100%; + float: left; + } + img { + float: left; + width: 100%; + height: 100%; + object-fit: contain; + } + .describe { + width: 100%; + height: 50px; + float: left; + margin-left: 15%; + margin-top: 5px; + p { + b { + //color: #e43933; + } + width: 40%; + text-align: left; + float: left; + margin: 4px 0px; + } + } + .describeBigImage { + width: 100%; + height: 50px; + float: left; + margin-top: 5px; + p { + b { + //color: #e43933; + } + width: 50%; + text-align: left; + float: left; + margin: 4px 0px; + } + } + } + .merge { + margin-top: 30px; + float: left; + } + } + .model-card-box-right { + padding-left: 5px; + box-sizing: border-box; + width: 40%; + overflow: auto; + height: 100%; + .img-box-title { + text-align: left; + margin: 5px; + } + .img-box { + height: 32%; + width: 100%; + position: relative; + .card-img-box-compear-left { + float: left; + width: 50%; + height: 100%; + img { + width: 100%; + height: 100%; + object-fit: contain; + //border: 1px solid rgb(92, 91, 91); + padding: 0px 4px; + box-sizing: border-box; + border-radius: 5px; + } + } + .card-img-box-compear-right { + float: right; + width: 50%; + height: 100%; + .el-carousel__container { + height: 100% !important; + .el-carousel__arrow { + top: 50% !important; + } + .el-carousel__arrow { + height: 20px; + width: 20px; + } + .el-carousel__arrow--right { + right: 10px !important; + } + .el-carousel__arrow--left { + left: 10px !important; + } + } + img { + width: 100%; + height: 100%; + object-fit: contain; + //border: 1px solid rgb(92, 91, 91); + padding: 0px 4px; + box-sizing: border-box; + border-left: none; + border-radius: 5px; + } + } + .img-compareScore { + bottom: 0px; + width: 60px; + height: 20px; + line-height: 20px; + background-color: #e43933; + position: absolute; + left: calc(50% - 30px); + border-top-right-radius: 5px; + border-top-left-radius: 5px; + color: #ebeef5; + font-weight: 700; + z-index: 2; + } + .imgs { + width: 50%; + height: 50%; + float: left; + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + padding-right: 5px; + box-sizing: border-box; + background-color: #ebeef5; + img { + width: 100%; + } + } + } + } + } +} +</style> diff --git a/src/components/subComponents/MultiRangeSlider.vue b/src/components/subComponents/MultiRangeSlider.vue new file mode 100644 index 0000000..5b8c0ac --- /dev/null +++ b/src/components/subComponents/MultiRangeSlider.vue @@ -0,0 +1,761 @@ +<template> + <div class="timeRangeSliderBox"> + <canvas :id="mainId" :ref="mainId" width="700px" height="260px">鎶辨瓑,鎮ㄧ殑娴忚鍣ㄤ笉鏀寔canvas!璇锋洿鎹㈡祻瑙堝櫒</canvas> + <canvas + :id="`${mainId}Dummy`" + :ref="`${mainId}Dummy`" + width="700px" + height="260px" + @dblclick="handlerClick" + @mouseout="mouseout($event)" + @mousedown="mouseDown($event)" + @mousemove="mousemove($event)" + @mouseup="mouseup($event)" + >鎶辨瓑,鎮ㄧ殑娴忚鍣ㄤ笉鏀寔canvas!璇锋洿鎹㈡祻瑙堝櫒</canvas> + <div class="popup-box" :style="`top:${popPos.y + 10}px;left:${popPos.x - 70}px`" v-if="isPopup"> + <div> + <b>寮�濮嬫椂闂�:</b> + <input + v-model="changeTime.startHour" + :min="0" + :max="changeTime.endHour" + type="number" + placeholder="鏃�" + /> + <b>:</b> + <input v-model="changeTime.startMin" type="number" placeholder="鍒�" /> + </div> + <div> + <b>缁撴潫鏃堕棿:</b> + <input + v-model="changeTime.endHour" + :min="changeTime.startHour" + :max="24" + type="number" + placeholder="鏃�" + /> + <b>:</b> + <input v-model="changeTime.endMin" type="number" placeholder="鍒�" /> + </div> + <div style="margin-top:5px;"> + <el-button @click="deleteRange">鍒犻櫎</el-button> + <el-button @click="cancalPop">鍙栨秷</el-button> + <el-button @click="timeAck">纭畾</el-button> + </div> + </div> + </div> +</template> + +<script> +export default { + mounted() { + + this.initMain(); + this.initMainDummy(); + }, + data() { + return { + x: "", + y: "", + isMouseDown: false, + isCreate: false, + isResizeLeft: false, + isResizeRight: false, + actRange: "", + actGrid: "", + rangeArr: [], + gridArr: [], + currentPointX: "", + actRangeIndex: "", + noLimit: 0, + isPopup: false, + popPos: { + x: "", + y: "" + }, + changeTime: { + startHour: "", + startMin: "", + endHour: "", + endMin: "" + }, + rangeArrBackup: "", + styleClass: { + weekTextColor: "", + minutePerColor: "#cdcdcd", + minutePerTextColor: "#808080" + } + }; + }, + props: { + timeData: { + default: () => { }, + type: Array + }, + mainId: { + type: String, + default: "" + }, + itemId: { + type: String, + default: "" + }, + itemName: { + type: String, + default: "" + }, + edit: { + type: Boolean, + default: false + } + }, + watch: { + changeTime: { + handler(newVal, oldVal) { + if (newVal.startHour >= 24) { + newVal.startHour = 24; + newVal.startMin = 0; + } + + if (newVal.endHour >= 24) { + newVal.endHour = 24; + newVal.endMin = 0; + } + + if (newVal.startHour < 0) { + newVal.startHour = 0; + } + + if (newVal.endHour < 0) { + newVal.endHour = newVal.startHour; + } + + if (newVal.startMin > 60) { + newVal.startMin = 0 + } + if (newVal.startMin < 0) { + newVal.startMin = 60 + } + if (newVal.endMin > 60) { + newVal.endMin = 0 + } + if (newVal.endMin < 0) { + newVal.endMin = 0 + } + + if (parseInt(newVal.startHour) == parseInt(newVal.endHour) && parseInt(newVal.startMin) > parseInt(newVal.endMin)) { + newVal.startMin = 0 + } + }, + deep: true + } + }, + methods: { + timeAck() { + let rangeInfo = this.actRange.rangeInfo; + let perH = 600 / 24; + let perM = perH / 60; + + let tempRangeInfo = this.rangeArr[rangeInfo.ownedIndex].rangeInfo; + tempRangeInfo.maxX = this.changeTime.endHour * perH + this.changeTime.endMin * perM + 50.5; + tempRangeInfo.minX = this.changeTime.startHour * perH + this.changeTime.startMin * perM + 50.5; + tempRangeInfo.width = tempRangeInfo.maxX - tempRangeInfo.minX; + for (let i = 0; i < this.gridArr.length; i++) { + let num = 0; + for (let j = 0; j < this.rangeArr.length; j++) { + if (this.gridArr[i].posIndex === this.rangeArr[j].rangeInfo.posIndex) { + this.gridArr[i].rangeList.splice(num, 1, this.rangeArr[j].rangeInfo); + num++; + } + } + } + this.cancalPop(); + this.redraw(false); + this.export(); + }, + deleteRange() { + this.rangeArr.splice(this.actRangeIndex, 1); + for (let i = 0; i < this.rangeArr.length; i++) { + this.rangeArr[i].rangeInfo.ownedIndex = i; + } + for (let i = 0; i < this.gridArr.length; i++) { + let num = 0; + for (let j = 0; j < this.rangeArr.length; j++) { + if ( + this.gridArr[i].posIndex === this.rangeArr[j].rangeInfo.posIndex + ) { + this.gridArr[i].rangeList.splice( + num, + 1, + this.rangeArr[j].rangeInfo + ); + num++; + } + } + } + this.cancalPop(); + this.redraw(false); + this.export(); + }, + getPopTime() { + let rangeInfo = this.actRange.rangeInfo; + if (!rangeInfo) { + return false; + } + let hourStart = parseInt((rangeInfo.minX - 50.5) / (600 / 24)); + let minutetStart = Math.round( + ((rangeInfo.minX - 50.5) % (600 / 24)) / (600 / 24 / 60) + ); + let hourEnd = parseInt((rangeInfo.maxX - 50.5) / (600 / 24)); + let minuteEnd = Math.round( + ((rangeInfo.maxX - 50.5) % (600 / 24)) / (600 / 24 / 60) + ); + minuteEnd = minuteEnd < 10 ? "0" + minuteEnd : minuteEnd; + this.changeTime.startHour = hourStart < 10 ? "0" + hourStart : hourStart; + this.changeTime.startMin = minutetStart === 60 ? "00" : minutetStart; + this.changeTime.endHour = hourEnd < 10 ? "0" + hourEnd : hourEnd; + this.changeTime.endMin = minuteEnd === 60 ? "00" : minuteEnd; + return true; + }, + cancalPop() { + this.isPopup = false; + this.actRange = ""; + this.actGrid = ""; + this.actRangeIndex = ""; + }, + handlerClick() { + if (this.getPopTime()) { + this.isPopup = true; + this.popPos.x = Number(JSON.stringify(this.x)); + this.popPos.y = Number(JSON.stringify(this.y >= 180 ? 170 : this.y)); + } + }, + mouseout(e) { + this.isMouseDown = false; + this.isCreate = false; + this.noLimit = 0; + }, + mouseup(e) { + this.isMouseDown = false; + this.isCreate = false; + // this.actRange = '' + // this.actGrid = '' + // this.actRangeIndex = '' + this.noLimit = 0; + if (this.rangeArrBackup !== JSON.stringify(this.rangeArr)) { + this.rangeArrBackup = JSON.stringify(this.rangeArr); + this.export(); + } + + this.redraw(false); + }, + mouseDown(e) { + this.isPopup = false; + this.isMouseDown = true; + this.currentPointX = e.offsetX; + this.noLimit++; + for (let i = 0; i < this.rangeArr.length; i++) { + let rangeItem = this.rangeArr[i].rangeInfo; + if ( + this.x > rangeItem.minX && + this.x < rangeItem.maxX && + this.y > rangeItem.minY && + this.y < rangeItem.maxY + ) { + this.actRange = this.rangeArr[i]; + this.actRangeIndex = i; + return; + } + } + for (let i = 0; i < this.gridArr.length; i++) { + if ( + this.x > this.gridArr[i].minX && + this.x < this.gridArr[i].maxX && + this.y > this.gridArr[i].minY && + this.y < this.gridArr[i].maxY + ) { + this.actGrid = this.gridArr[i]; + return; + } + } + }, + mousemove(e) { + if (!this.edit) { + return; + } + + if (this.isPopup) { + return; + } + // let canvas = document.getElementById(`${this.mainId}Dummy`); + let canvas = this.$refs[`${this.mainId}Dummy`]; + let ctx = canvas.getContext("2d"); + this.x = e.offsetX; + this.y = e.offsetY; + if ( + this.actRange && + this.isMouseDown && + !this.isCreate && + !this.isResizeLeft && + !this.isResizeRight + ) { + // console.log("move", this.actRange); + let diff = e.offsetX - this.currentPointX; + let tempMinxX = this.actRange.rangeInfo.minX + diff; + let limit = this.limit(this.actRange); + if ( + tempMinxX <= limit.limitLeft || + tempMinxX + this.actRange.rangeInfo.width >= limit.limitRight + ) { + return; + } + this.actRange.rangeInfo.minX = tempMinxX; + this.actRange.rangeInfo.maxX = tempMinxX + this.actRange.rangeInfo.width; + this.currentPointX = e.offsetX; + let tempRangeList = this.gridArr[this.actRange.rangeInfo.posIndex].rangeList; + this.redraw(); + // console.log("move-ed"); + } else if ( + this.actGrid && + this.isMouseDown && + !this.isResizeLeft && + !this.isResizeRight + ) { + // console.log("create"); + if (this.isCreate) { + let limit = this.limit(this.actRange); + if ( + this.actRange.rangeInfo.minX <= limit.limitLeft || + this.actRange.rangeInfo.minX + this.actRange.rangeInfo.width >= + limit.limitRight + ) { + return; + } + let tempX + if (this.x < 50) { + tempX = 50 + } else if (this.x > 650) { + tempX = 650 + } else { + tempX = this.x + } + let temp = tempX - this.currentPointX > 0 ? true : false; + let newWith = 0; + if (temp) { + newWith = tempX - this.currentPointX; + this.actRange.rangeInfo.maxX = tempX; + } else { + newWith = this.currentPointX - tempX; + this.actRange.rangeInfo.maxX = this.currentPointX; + this.actRange.rangeInfo.minX = tempX; + } + this.actRange.rangeInfo.width = newWith; + this.redraw(); + return; + } + let tempRangeList = this.actGrid.rangeList; + if (tempRangeList) { + let rangeObj = { + end: "", + start: "", + rangeInfo: { + minX: this.currentPointX, + minY: this.actGrid.minY, + maxX: this.currentPointX + 10, + maxY: this.actGrid.maxY, + width: 10, + height: 14, + posIndex: this.actGrid.posIndex, + ownedIndex: 0 + } + }; + let actRangeIndex = 0; + for (let i = 0; i < tempRangeList.length; i++) { + if (this.currentPointX > tempRangeList[i].minX) { + actRangeIndex++; + } + } + this.actRangeIndex = actRangeIndex; + this.rangeArr.splice(this.actRangeIndex, 0, rangeObj); + for (let i = 0; i < this.rangeArr.length; i++) { + this.rangeArr[i].rangeInfo.ownedIndex = i; + } + for (let i = 0; i < this.gridArr.length; i++) { + let num = 0; + for (let j = 0; j < this.rangeArr.length; j++) { + if ( + this.gridArr[i].posIndex === this.rangeArr[j].rangeInfo.posIndex + ) { + this.gridArr[i].rangeList.splice( + num, + 1, + this.rangeArr[j].rangeInfo + ); + num++; + } + } + } + this.actGrid.rangeList = this.gridArr[ + this.actGrid.posIndex + ].rangeList; + this.actRange = this.rangeArr[this.actRangeIndex]; + this.isCreate = true; + } + } else if ( + this.isMouseDown && + (this.isResizeLeft || this.isResizeRight) && + this.actRange !== "" && + this.actRangeIndex !== "" + ) { + // console.log("resize"); + let limit = this.limit(this.actRange); + if ( + (this.actRange.rangeInfo.minX <= limit.limitLeft || + this.actRange.rangeInfo.minX + this.actRange.rangeInfo.width >= + limit.limitRight) && + this.noLimit > 5 + ) { + this.isResizeRight = false; + this.isResizeLeft = false; + this.actRange = ""; + this.actRangeIndex = ""; + return; + } + if (this.isResizeLeft) { + if ( + this.x > + this.actRange.rangeInfo.width / 2 + this.actRange.rangeInfo.minX - 5 + ) { + return; + } + this.actRange.rangeInfo.minX = this.x < 50 ? 50 : this.x; + this.actRange.rangeInfo.width = this.actRange.rangeInfo.maxX - this.x; + this.noLimit++; + this.redraw(); + return; + } else if (this.isResizeRight) { + if ( + this.x < + this.actRange.rangeInfo.width / 2 + this.actRange.rangeInfo.minX + 5 + ) { + return; + } + this.actRange.rangeInfo.maxX = this.x > 650 ? 650 : this.x; + this.actRange.rangeInfo.width = this.actRange.rangeInfo.maxX - this.actRange.rangeInfo.minX; + this.noLimit++; + this.redraw(); + return; + } + } else { + for (let i = 0; i < this.rangeArr.length; i++) { + let rangeItem = this.rangeArr[i].rangeInfo; + if ( + this.x > rangeItem.minX && + this.x < rangeItem.minX + 6 && + this.y > rangeItem.minY && + this.y < rangeItem.maxY + ) { + this.isResizeLeft = true; + document.documentElement.style.cursor = "col-resize"; + this.actRange = this.rangeArr[i]; + this.actRangeIndex = i; + return; + } else if ( + this.x > rangeItem.maxX - 6 && + this.x < rangeItem.maxX && + this.y > rangeItem.minY && + this.y < rangeItem.maxY + ) { + this.isResizeRight = true; + document.documentElement.style.cursor = "col-resize"; + this.actRange = this.rangeArr[i]; + this.actRangeIndex = i; + return; + } else { + this.isResizeRight = false; + this.isResizeLeft = false; + this.actRange = ""; + this.actRangeIndex = ""; + document.documentElement.style.cursor = "default"; + } + } + } + }, + limit(rangeObj) { + let before = this.rangeArr[this.actRangeIndex - 1]; + let behind = this.rangeArr[this.actRangeIndex + 1]; + let obj = { + limitLeft: 50, + limitRight: 650 + }; + if (before === undefined && behind === undefined) { + return obj; + } + if (before === undefined) { + obj.limitLeft = 50; + obj.limitRight = + behind.rangeInfo.posIndex === rangeObj.rangeInfo.posIndex + ? behind.rangeInfo.minX + : 650; + return obj; + } else if (behind === undefined) { + obj.limitLeft = + before.rangeInfo.posIndex === rangeObj.rangeInfo.posIndex + ? before.rangeInfo.maxX + : 50; + obj.limitRight = 650; + return obj; + } + if ( + before.rangeInfo.posIndex === rangeObj.rangeInfo.posIndex && + behind.rangeInfo.posIndex === rangeObj.rangeInfo.posIndex + ) { + obj.limitLeft = before.rangeInfo.maxX; + obj.limitRight = behind.rangeInfo.minX; + } else if ( + before.rangeInfo.posIndex !== rangeObj.rangeInfo.posIndex && + behind.rangeInfo.posIndex === rangeObj.rangeInfo.posIndex + ) { + obj.limitLeft = 50; + obj.limitRight = behind.rangeInfo.minX; + } else if ( + before.rangeInfo.posIndex === rangeObj.rangeInfo.posIndex && + behind.rangeInfo.posIndex !== rangeObj.rangeInfo.posIndex + ) { + obj.limitLeft = before.rangeInfo.maxX; + obj.limitRight = 650; + } else { + obj.limitLeft = 50; + obj.limitRight = 650; + } + return obj; + }, + weekString(n) { + let base = "鏄熸湡"; + switch (n) { + case 1: + return base + "涓�"; + case 2: + return base + "浜�"; + case 3: + return base + "涓�"; + case 4: + return base + "鍥�"; + case 5: + return base + "浜�"; + case 6: + return base + "鍏�"; + case 7: + return base + "鏃�"; + } + }, + initMain() { + // let canvas = document.getElementById(`${this.mainId}`); + let canvas = this.$refs[`${this.mainId}`]; + let ctx = canvas.getContext("2d"); + ctx.font = "12px Arial"; + let height = 260; + let width = canvas.offsetWidth; + let per = height / 7; + for (let i = 0; i < 7; i++) { + // let weekText = `鏄熸湡${this.timeData[i].day}:`; + let weekText = this.weekString(this.timeData[i].day); + let mid = per * i + per / 2 + 6.5; + ctx.strokeStyle = this.styleClass.minutePerColor; + ctx.fillText(weekText, 10, mid); + let startX = 50.5; + let startY = mid - 10; + ctx.save(); + ctx.strokeStyle = "#DCDFE6"; + ctx.fillStyle = "#DCE9FF"; + ctx.fillRect(startX, startY, 600, 14); + ctx.strokeRect(startX, startY, 600, 14); + ctx.restore(); + let tempGrid = { + minX: startX, + minY: startY, + maxX: startX + 600, + maxY: startY + 14, + width: 600, + height: 14, + posIndex: i, + rangeList: [] + }; + this.gridArr.push(tempGrid); + let timePer = 600 / 24; + for (let j = 0; j < 25; j++) { + let x = startX + timePer * j; + let y = startY; + let delVar = j % 2 === 0 ? 6.5 : 3.5; + ctx.save(); + ctx.moveTo(x, y - delVar); + ctx.lineTo(x, y); + ctx.stroke(); + ctx.font = "10px Arial"; + ctx.fillStyle = this.styleClass.minutePerTextColor; + ctx.fillText(j, x - (j > 9 ? 4.5 : 2.5), y - 8.5); + ctx.restore(); + } + } + }, + initMainDummy() { + let canvas = document.getElementById(`${this.mainId}Dummy`); + let ctx = canvas.getContext("2d"); + let height = 260; + let startX = 50.5; + let per = height / 7; + let hourPer = 600 / 24; + let minutePer = hourPer / 60; + for (let i = 0; i < this.timeData.length; i++) { + let mid = per * i + per / 2 + 6.5; + let startY = mid - 10; + let rang = this.timeData[i].time_range; + for (let j = 0; j < rang.length; j++) { + let start = rang[j].start.split(":"); + let end = rang[j].end.split(":"); + let startRange = + hourPer * Number(start[0]) + minutePer * Number(start[1]); + let endRange = hourPer * Number(end[0]) + minutePer * Number(end[1]); + let diffRange = Math.abs(endRange - startRange); + let rectStartX = + (startRange > endRange ? endRange : startRange) + 50.5; + ctx.fillStyle = "#6B9EFF"; + ctx.fillRect(rectStartX, startY, diffRange, 14); + let rangeInfo = { + minX: rectStartX, + minY: startY, + maxX: rectStartX + diffRange, + maxY: startY + 14, + width: diffRange, + height: 14, + posIndex: i, + ownedIndex: this.rangeArr.length + }; + rang[j].rangeInfo = rangeInfo; + this.gridArr[i].rangeList.push(rangeInfo); + this.rangeArr.push(rang[j]); + } + } + + this.rangeArrBackup = JSON.stringify(this.rangeArr); + }, + redraw(onlyDraw = true) { + let canvas = document.getElementById(`${this.mainId}Dummy`); + let ctx = canvas.getContext("2d"); + ctx.clearRect(0, 0, 700, 260); + if (onlyDraw) { + let rangeInfo = this.actRange.rangeInfo; + let hourStart = parseInt((rangeInfo.minX - 50) / (600 / 24)); + let minutetStart = Math.round( + ((rangeInfo.minX - 50) % (600 / 24)) / (600 / 24 / 60) + ); + let hourEnd = parseInt((rangeInfo.maxX - 50) / (600 / 24)); + let minuteEnd = Math.round( + ((rangeInfo.maxX - 50) % (600 / 24)) / (600 / 24 / 60) + ); + minuteEnd = minuteEnd < 10 ? "0" + minuteEnd : minuteEnd; + let textStart = `${hourStart < 10 ? "0" + hourStart : hourStart}:${ + minutetStart === 60 ? "00" : minutetStart + }`; + let textEnd = `${hourEnd < 10 ? "0" + hourEnd : hourEnd}:${ + minuteEnd === 60 ? "00" : minuteEnd + }`; + let startPointX = rangeInfo.minX - 14; + let startPointY = rangeInfo.maxY + 10; + let endPointX = rangeInfo.maxX - 13; + let endPointY = rangeInfo.maxY + 10; + ctx.fillStyle = "#303133"; + ctx.fillText(textStart, startPointX, startPointY); + ctx.fillText(textEnd, endPointX, endPointY); + } + for (let i = 0; i < this.rangeArr.length; i++) { + ctx.fillStyle = "#6B9EFF"; + ctx.fillRect( + this.rangeArr[i].rangeInfo.minX, + this.rangeArr[i].rangeInfo.minY, + this.rangeArr[i].rangeInfo.width, + this.rangeArr[i].rangeInfo.height + ); + } + }, + export() { + let timeRule = []; + for (let i = 0; i < 7; i++) { + timeRule.push({ + day: i + 1, + time_range: (() => { + let range = []; + this.rangeArr.forEach(item => { + if (item.rangeInfo.posIndex === i) { + let rangeInfo = item.rangeInfo; + let hourStart = parseInt((rangeInfo.minX - 50.5) / (600 / 24)); + let minutetStart = Math.round( + ((rangeInfo.minX - 50.5) % (600 / 24)) / (600 / 24 / 60) + ); + let hourEnd = parseInt((rangeInfo.maxX - 50.5) / (600 / 24)); + let minuteEnd = Math.round( + ((rangeInfo.maxX - 50.5) % (600 / 24)) / (600 / 24 / 60) + ); + hourStart = hourStart < 10 ? "0" + hourStart : hourStart; + minutetStart = + minutetStart < 10 ? "0" + minutetStart : minutetStart; + hourEnd = hourEnd < 10 ? "0" + hourEnd : hourEnd; + minuteEnd = minuteEnd < 10 ? "0" + minuteEnd : minuteEnd; + range.push({ + start: hourStart + ":" + minutetStart, + end: hourEnd + ":" + minuteEnd + }); + } + }); + return range; + })() + }); + } + + let obj = { + id: this.itemId, + name: this.itemName, + time_rule: timeRule + }; + this.$emit("range-update", obj); + } + } +}; +</script> + +<style lang="scss"> +.timeRangeSliderBox { + width: 700px; + height: 260px; + text-align: left; + margin: 10px auto; + position: relative; + canvas { + position: absolute; + top: 0px; + left: 0px; + width: 700px; + height: 260px; + } + .popup-box { + width: 160px; + height: 80px; + background-color: rgba(0, 0, 0, 0.6); + border-radius: 5px; + position: relative; + padding: 5px; + box-sizing: border-box; + color: #fff; + input { + width: 33px; + } + div { + margin: 3px auto; + text-align: center; + } + button { + padding: 3px; + } + } +} +</style> \ No newline at end of file diff --git a/src/components/subComponents/ParticleNetwork.vue b/src/components/subComponents/ParticleNetwork.vue new file mode 100644 index 0000000..1989781 --- /dev/null +++ b/src/components/subComponents/ParticleNetwork.vue @@ -0,0 +1,351 @@ +<template> + <div class="particle-network-animation" :style="`height:${height}px;width:${width}px`"> + <div style="display:none"> + <img ref="conf0" src="../../assets/img/login/0.png" /> + <img ref="conf1" src="../../assets/img/login/1.png" /> + <img ref="conf2" src="../../assets/img/login/2.png" /> + <img ref="conf3" src="../../assets/img/login/3.png" /> + <img ref="conf4" src="../../assets/img/login/4.png" /> + <img ref="conf5" src="../../assets/img/login/5.png" /> + <img ref="conf6" src="../../assets/img/login/6.png" /> + <img ref="conf7" src="../../assets/img/login/7.png" /> + <img ref="conf8" src="../../assets/img/login/8.png" /> + <img ref="conf9" src="../../assets/img/login/9.png" /> + <img ref="conf10" src="../../assets/img/login/10.png" /> + <img ref="conf11" src="../../assets/img/login/11.png" /> + <img ref="conf12" src="../../assets/img/login/12.png" /> + <img ref="conf13" src="../../assets/img/login/13.png" /> + <img ref="conf14" src="../../assets/img/login/14.png" /> + <img ref="conf15" src="../../assets/img/login/15.png" /> + </div> + </div> +</template> + +<script> +export default { + name: "particleNetwork", + data() { + return { + imgNumber: 0, + destoryed: false + }; + }, + props: { + height: { + type: Number, + default: 800 + }, + width: { + type: Number, + default: 1000 + } + }, + mounted() { + this.createCavas(); + }, + beforeDestroy() { + this.destoryed = true + }, + methods: { + createCavas() { + let that = this; + var ParticleNetworkAnimation, PNA; + ParticleNetworkAnimation = PNA = function () { }; + + PNA.prototype.init = function (element) { + // this.$el = $(element); + + this.container = element; + this.canvas = document.createElement("canvas"); + this.sizeCanvas(); + this.container.appendChild(this.canvas); + this.ctx = this.canvas.getContext("2d"); + this.particleNetwork = new ParticleNetwork(this); + + return this; + }; + + PNA.prototype.sizeCanvas = function () { + this.canvas.width = this.container.offsetWidth; + this.canvas.height = this.container.offsetHeight; + }; + + var Particle = function (parent, x, y) { + this.network = parent; + this.imgNumber = that.imgNumber++; + this.canvas = parent.canvas; + this.ctx = parent.ctx; + this.particleColor = returnRandomArrayitem( + this.network.options.particleColors + ); + // 鎺у埗澶у皬 + this.radius = getLimitedRandom(10, 30); + this.opacity = 0; + // this.x = x || Math.random() * this.canvas.width; + // this.y = y || Math.random() * this.canvas.height; + + // 鎺у埗鍒濆鍧愭爣锛屼笉瑕佽秴鍑鸿寖鍥� + this.x = x || getLimitedRandom(50, this.canvas.width - 50); + this.y = y || getLimitedRandom(50, this.canvas.height - 50); + + this.velocity = { + x: (Math.random() - 0.5) * parent.options.velocity, + y: (Math.random() - 0.5) * parent.options.velocity + }; + }; + + Particle.prototype.update = function () { + if (this.opacity < 0.8) { + this.opacity += 0.01; + } else { + this.opacity = 0.8; + } + // 绉诲姩鍒拌竟缂樻椂鍙嶅悜 + if (this.x > this.canvas.width - 50 || this.x < 50) { + this.velocity.x = -this.velocity.x; + } + if (this.y > this.canvas.height - 50 || this.y < 50) { + this.velocity.y = -this.velocity.y; + } + + // 鏇存柊鍧愭爣 + this.x += this.velocity.x; + this.y += this.velocity.y; + }; + + Particle.prototype.draw = function () { + // Draw particle + if (that.destoryed) { + return; + } + this.ctx.beginPath(); + this.ctx.fillStyle = this.particleColor; + this.ctx.globalAlpha = this.opacity; + this.ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI); + this.ctx.fill(); + var prop = this.radius; + // let imgOdr = parseInt(Math.random() * 16, 10); + var img = that.$refs["conf" + this.imgNumber]; + // img.src = "../../assets/img/login/" + imgOdr + ".png"; + this.ctx.drawImage( + img, + this.x - this.radius * 0.8, + this.y - this.radius * 0.8, + this.radius * 1.6, + this.radius * 1.6 + ); + }; + + var ParticleNetwork = function (parent) { + this.options = { + velocity: 1, // the higher the faster + density: 1500, // the lower the denser + netLineDistance: 300, + netLineColor: "#477bec", + particleColors: ["#7E8BFA"] // ['#6D4E5C', '#aaa', '#FFC458' ] + }; + this.canvas = parent.canvas; + this.ctx = parent.ctx; + + this.init(); + }; + + ParticleNetwork.prototype.init = function () { + // Create particle objects + this.createParticles(true); + + // Update canvas + this.animationFrame = requestAnimationFrame(this.update.bind(this)); + }; + + ParticleNetwork.prototype.createParticles = function (isInitial) { + // Initialise / reset particles + var me = this; + this.particles = []; + // var quantity = this.canvas.width * this.canvas.height / this.options.density; + var quantity = 17; + + if (isInitial) { + var counter = 0; + clearInterval(this.createIntervalId); + this.createIntervalId = setInterval( + function () { + if (counter < quantity - 1) { + // Create particle object + this.particles.push(new Particle(this)); + } else { + clearInterval(me.createIntervalId); + } + counter++; + }.bind(this), + 250 + ); + } else { + // Create particle objects + for (var i = 0; i < quantity; i++) { + this.particles.push(new Particle(this)); + } + } + }; + + ParticleNetwork.prototype.destory = function (isInitial) { + clearInterval(this.createIntervalId); + }; + ParticleNetwork.prototype.update = function () { + if (this.canvas) { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.globalAlpha = 1; + + // Draw connections + for (var i = 0; i < this.particles.length; i++) { + for (var j = this.particles.length - 1; j > i; j--) { + var distance, + p1 = this.particles[i], + p2 = this.particles[j]; + + // check very simply if the two points are even a candidate for further measurements + distance = Math.min(Math.abs(p1.x - p2.x), Math.abs(p1.y - p2.y)); + if (distance > this.options.netLineDistance) { + continue; + } + + // the two points seem close enough, now let's measure precisely + distance = Math.sqrt( + Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2) + ); + if (distance > this.options.netLineDistance) { + continue; + } + + this.ctx.beginPath(); + this.ctx.strokeStyle = this.options.netLineColor; + this.ctx.globalAlpha = + ((this.options.netLineDistance - distance) / + this.options.netLineDistance) * + p1.opacity * + p2.opacity; + this.ctx.lineWidth = 1.7; + this.ctx.moveTo(p1.x, p1.y); + this.ctx.lineTo(p2.x, p2.y); + this.ctx.stroke(); + } + } + + // Draw particles + for (var i = 0; i < this.particles.length; i++) { + this.particles[i].update(); + this.particles[i].draw(); + } + + if (this.options.velocity !== 0) { + this.animationFrame = requestAnimationFrame(this.update.bind(this)); + } + } else { + cancelAnimationFrame(this.animationFrame); + } + }; + + var getLimitedRandom = function (min, max, roundToInteger) { + var number = Math.random() * (max - min) + min; + if (roundToInteger) { + number = Math.round(number); + } + return number; + }; + + var returnRandomArrayitem = function (array) { + return array[Math.floor(Math.random() * array.length)]; + }; + + var elm = document.getElementsByClassName( + "particle-network-animation" + )[0]; + + this.pna = new ParticleNetworkAnimation(); + this.pna.init(elm); + } + } +}; +</script> + +<style lang="scss"> +.particle-network-animation { + position: fixed; + top: 20%; + left: 0; + right: 0; + // background-color: #171717; +} +.particle-network-animation::before { + z-index: -3; + content: ""; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-size: cover; + opacity: 0.2; +} + +.glow { + z-index: -2; + position: fixed; + top: 50%; + left: 50%; + background-image: radial-gradient( + circle closest-side, + rgba(255, 255, 255, 0.025), + transparent + ); +} + +.glow-1 { + width: 150vw; + height: 150vh; + margin-top: -75vh; + margin-left: -75vw; + animation: glow-1-move 25s linear infinite both; +} + +@keyframes glow-1-move { + from { + transform: translate(-100%, 100%); + } + to { + transform: translate(100%, -100%); + } +} +.glow-2 { + width: 100vw; + height: 100vh; + margin-top: -50vh; + margin-left: -50vw; + animation: glow-2-move 25s linear 8.3333333333s infinite both; +} + +@keyframes glow-2-move { + from { + transform: translate(-100%, 0%); + } + to { + transform: translate(100%, 100%); + } +} +.glow-3 { + width: 120vw; + height: 120vh; + margin-top: -60vh; + margin-left: -60vw; + animation: glow-3-move 25s linear 16.6666666667s infinite both; +} + +@keyframes glow-3-move { + from { + transform: translate(100%, 100%); + } + to { + transform: translate(0%, -100%); + } +} +</style> \ No newline at end of file diff --git a/src/components/subComponents/RuleEditor.vue b/src/components/subComponents/RuleEditor.vue new file mode 100644 index 0000000..2f54f55 --- /dev/null +++ b/src/components/subComponents/RuleEditor.vue @@ -0,0 +1,811 @@ +<template> + <div class="edit-rules-box"> + <p style="padding: 0"> + <b style="font-size: 14px; line-height: 28px;">绛栫暐閰嶇疆</b> + <span class="btn" @click="createRule" v-if="groupRules.length === 0"> + <i class="iconfont iconhebingxingzhuang" style="font-size:16px"></i> + 鏂板 + </span> + + <span class="btn" @click="cleanRule" v-if="groupRules.length > 0"> + <i class="iconfont iconshanchu11" style="font-size:16px"></i> + 娓呯┖ + </span> + </p> + <div class="sub-task-rules-box"> + <span class="task-blank" v-show="groupRules.length == 0 ">鏆傛棤瑙勫垯锛岃閫夋嫨鏂板瑙勫垯閰嶇疆</span> + <div style=" text-align: left;" v-for="(rule, index) in groupRules" :key="index"> + <div style="margin-left:10px;margin-top: 4px;" v-show="index > 0"> + <el-select v-model="rule.rule_with_pre" placeholder="骞跺垪鍏崇郴" size="mini"> + <el-option + v-for="subitem in VideoManageData.Dictionary.RULECOMPUTEBETWEEN" + :key="subitem.id" + :label="subitem.name" + :value="subitem.value" + :title="subitem.name" + ></el-option> + </el-select> + </div> + + <div style="margin-left:10px;"> + <!-- 閫夋嫨鍖哄煙 --> + <el-select + v-model="rule.polygonObj" + v-if="!isTemplate" + value-key="polygonId" + placeholder="閫夋嫨鍖哄煙" + size="mini" + @change="selectPolygonOption(rule)" + > + <el-option + v-for="subitem in allPolygonData" + :key="subitem.id" + :label="subitem.name" + :value="subitem" + :title="subitem.name" + ></el-option> + </el-select> + + <!-- 閫夋嫨绠楁硶 --> + <el-select + v-model="rule.sdkObj" + value-key="id" + placeholder="閫夋嫨绠楁硶" + size="mini" + @change="selectSDKOption(rule, true)" + > + <el-option + v-for="subitem in rule.sdksOptions" + :key="subitem.id" + :label="subitem.sdk_name" + :value="subitem" + :title="subitem.sdk_name" + v-show="!subitem.delete" + ></el-option> + </el-select> + + <!-- 閫夋嫨绫诲瀷 --> + <el-select + v-model="rule.sdk_arg_type" + placeholder="鐩爣" + size="mini" + style="width:90px;" + @change="selectArgTypeOption(rule)" + > + <el-option value="target" label="鐩爣"></el-option> + <el-option value="label" label="鏍囩"></el-option> + </el-select> + + <!-- 閫夋嫨瑙勫垯 --> + <el-select + v-model="rule.argObj" + value-key="alias" + placeholder="閫夋嫨瑙勫垯" + size="mini" + @change="selectArgsOption(rule, true)" + > + <el-option + v-for="subitem in rule.argsOptions" + :key="subitem.alias" + :label="subitem.name" + :value="subitem" + :title="subitem.name" + ></el-option> + </el-select> + + <!-- 閫夋嫨鏉′欢 --> + <el-select + v-model="rule.operatorObj" + value-key="value" + placeholder="閫夋嫨鏉′欢" + size="mini" + style="min-width:100px;width:8%" + @change="setOperator(rule)" + > + <el-option + v-for="subitem in VideoManageData.Dictionary.RULECOMPUTE" + :key="subitem.value" + :label="subitem.name" + :value="subitem" + ></el-option> + </el-select> + + <!-- 鍊肩被鍨� --> + <el-select + v-show="false" + v-model="rule.operator_type" + placeholder="鍊肩被鍨�" + size="mini" + style="min-width:100px;width:8%" + @change="selectValueOption(rule)" + > + <el-option value="value" label="鍊�" :disabled="rule.argType === 'option'"></el-option> + <el-option value="option" label="琚�夐」" :disabled="rule.argType !== 'option'"></el-option> + <el-option value label="绌�" :disabled="rule.argType === 'option'"></el-option> + </el-select> + + <!-- 鍊� --> + <el-input + v-if="rule.operator_type !== 'option'" + size="mini" + v-model="rule.sdk_arg_value" + :style="rule.valid ? `margin:3px 5px;min-width:100px;width:7%` : `margin:3px 5px;min-width:100px;width:7%;border:1px solid red`" + @change="setValue(rule)" + ></el-input> + + <!-- 閫夐」鍊� --> + <el-select + v-else + v-model="rule.valueObj" + value-key="value" + size="mini" + style="width:8%;min-width:100px" + @change="setValue(rule)" + > + <el-option + v-for="subitem in rule.valueOptions" + :key="subitem.value" + :label="subitem.name" + :value="subitem" + :title="subitem.name" + ></el-option> + </el-select> + + <!-- 鍗曚綅 --> + <span style="display:inline-block;width:15px;margin-right:10px;">{{ rule.unit }}</span> + + <!-- 鏂板銆佸垹闄� 鎸夐挳 --> + <el-button type="text" @click="addRule(index)" class="iconfont iconhebingxingzhuang"></el-button> + <el-button + type="text" + style="color: #F53D3D;" + class="iconfont iconshanchu11" + @click="groupRules.splice(index, 1)" + ></el-button> + </div> + </div> + </div> + </div> +</template> +<script> +import { + deleteCameraRules, + updateRuleDefence, + updateAlarmLevel +} from "@/api/camera"; + +export default { + name: "SceneRuleEditor", + props: { + Cameras: { + type: Array, + default: () => { + return [] + } + }, + isTemplate: { + type: Boolean, + default: false + }, + isLinkRule: { + type: Boolean, + default: false + }, + includeSdks: { + type: Array + }, + ruleList: { + type: String, + default: "{}" + }, + onSubmitRule: { + type: Function, + default: () => false + } + }, + computed: { + allPolygonData() { + let polygon = []; + let cameras = [...this.Cameras]; + + for (let i = 0; i < cameras.length; i++) { + let polyOpt = cameras[i].polygonData.map(p => { + return { + defence_state: p.defence_state, + polygonId: p.id, + name: this.isLinkRule + ? cameras[i].cameraName + ":" + p.name + : p.name, + + cameraId: cameras[i].cameraId + }; + }); + + polygon = polygon.concat(polyOpt); + } + return polygon; + } + }, + watch: { + ruleList: { + handler(newVal, oldVal) { + this.editHandle(newVal); + }, + deep: true + }, + }, + mounted() { + this.editHandle(this.ruleList); + }, + data() { + return { + tasksTable: {}, + groupRules: [], + sdksOption: [], + baseRule: { + camera_id: "", + id: "", + operator: "", + operator_type: "", + polygon_id: "", + rule_with_pre: "", + sdk_id: "", + sdk_arg_alias: "", + sdk_arg_value: "", + sdk_arg_defaultValue: "", + select_time_rule: "", + sdk_arg_type: "", + // task_id: "", + + polygonObj: {}, + taskObj: "", + + sdkObj: {}, + argObj: {}, + operatorObj: {}, + valueObj: {}, + + sdksOptions: [], + argsOptions: [], + argType: "", + computeOptions: [], + valueOptions: [], + + sdkDesc: "", + argDesc: "", + operatorDesc: "", + typeDesc: "", + valueDesc: "", + + unit: "", + value: "", + valid: true + }, + }; + }, + methods: { + setSdksOptions(rule) { + rule.sdksOptions = this.includeSdks; + }, + setOperator(rule) { + rule.operator = rule.operatorObj.value; + rule.operatorDesc = rule.operatorObj.name; + }, + setValue(rule) { + rule.valid = true + + if (rule.operator_type === "option") { + rule.sdk_arg_value = rule.valueObj.value ? rule.valueObj.value : ""; + rule.typeDesc = "琚�夐」"; + rule.valueDesc = rule.valueObj.name ? rule.valueObj.name : ""; + } else { + rule.typeDesc = "鍊�"; + rule.valueDesc = rule.sdk_arg_value; + } + this.valideArgValue(rule) + }, + selectPolygonOption(rule) { + rule.polygon_id = rule.polygonObj.polygonId ? rule.polygonObj.polygonId : rule.polygon_id; + rule.camera_id = rule.polygonObj.cameraId ? rule.polygonObj.cameraId : rule.camera_id; + rule.group_id = this.group_id; + }, + selectSDKOption(rule, resetArgs) { + rule.sdk_id = rule.sdkObj.id; + rule.sdkDesc = `<span style="background-color:RGB(183,183,183);">${rule.sdkObj.sdk_name}</span>`; + + // 閫夐」鍒囨崲鏃堕渶瑕佸埛鏂癮rg鑿滃崟椤� + this.selectArgTypeOption(rule, resetArgs) + }, + selectArgTypeOption(rule, resetAlias) { + if (rule.sdk_arg_type == "") { + return + } + + if (resetAlias) { + rule.sdk_arg_alias = ""; + } + + rule.argsOptions = rule.sdkObj.args; + + // 鏍规嵁arg绫诲瀷鏄剧ず鍙傛暟, 褰撳墠鍏ㄩ儴褰掍负 target + // if (rule.sdkObj.args) { + // rule.argsOptions = rule.sdkObj.args.filter(ele => { + // return ele.arg_type === rule.sdk_arg_type + // }); + // } else { + // rule.argsOptions = []; + // } + + rule.argObj = {}; + }, + selectArgsOption(rule, resetArgValue) { + // rule.operator_type = ""; + // console.log(rule, '閫夋嫨绠楁硶鍙傛暟') + rule.sdk_arg_alias = rule.argObj.alias; + rule.argDesc = rule.argObj.name; + rule.sdk_arg_defaultValue = rule.argObj.default_value + rule.unit = rule.argObj.unit ? rule.argObj.unit : ""; + //rule.default_value = rule.argObj.default_value ? Number(rule.argObj.default_value) : 0; + + //console.log("缃俊搴︾殑榛樿鍊间负",rule.sdk_arg_defaultValue) + // 淇濆瓨鍊肩被鍨� + rule.argType = rule.argObj.type; + if (rule.argType === "option") { + rule.operator_type = "option"; + // 璁剧疆榛樿鏉′欢鍊� + this.VideoManageData.Dictionary.RULECOMPUTE.forEach(opt => { + if (opt.value == "==") { + rule.operatorObj = opt; + } + }); + + this.setOperator(rule); + + this.selectValueOption(rule); + } else { + // 璁剧疆榛樿鏉′欢鍊� + rule.operator_type = "value"; + if (resetArgValue) { + rule.sdk_arg_value = "" + + this.VideoManageData.Dictionary.RULECOMPUTE.forEach(opt => { + if (opt.value == ">=") { + rule.operatorObj = opt; + } + }); + } else { + // 缂栬緫瑙勫垯鍖归厤 + this.VideoManageData.Dictionary.RULECOMPUTE.forEach(opt => { + if (opt.value == rule.operator) { + rule.operatorObj = opt; + } + }); + } + this.setOperator(rule); + } + }, + selectValueOption(rule) { + if (rule.sdk_arg_alias === "time_rule") { + rule.valueOptions = this.VideoManageData.TimeRules.map(r => { + return { + name: r.name, + value: r.id + }; + }); + } else if (rule.sdk_arg_alias === "compareBase") { + rule.valueOptions = this.VideoManageData.TagList.map(r => { + return { + name: r.tableName, + value: r.id + }; + }); + } else { + let ops = this.VideoManageData.Dictionary[rule.sdk_arg_alias] + if (ops && ops instanceof (Array)) { + rule.valueOptions = ops.map(r => { + return { + name: r.name, + value: r.value + } + }) + } + } + }, + valideArgValue(rule) { + if (rule.sdk_arg_value == "") { + this.$notify({ + type: 'warning', + message: "鍙傛暟璁惧畾鍊间笉鑳戒负绌�!" + }) + rule.valid = false + return false + } + + if (rule.argObj && rule.argObj.range) { + // 濡傛灉璁剧疆浜嗙畻娉曢粯璁ゅ�硷紝鍒欏垽鏂笉鑳藉皬浜庤鍊� + if (rule.argObj.default_value) { + if (parseInt(rule.sdk_arg_value) < parseInt(rule.sdk_arg_defaultValue)) { + rule.valid = false + this.$notify({ + type: "warning", + message: "鍙傛暟璁惧畾鍊间笉鑳藉皬浜庣畻娉曞弬鏁伴粯璁ゅ�� " + rule.sdk_arg_defaultValue + }) + rule.valueDesc = rule.sdk_arg_value = rule.argObj.default_value; + rule.valid = false + return false; + } + } + + // let re = /(?<=,).*?(?=]|\))/ + let re = /.*,(\d+)/ + let max = rule.argObj.range.match(re)[1] + // console.log(max,'鑾峰彇鑼冨洿鏈�澶у��') + if (Number(rule.sdk_arg_value) > Number(max)) { + rule.valid = false + this.$notify({ + type: 'warning', + message: "鍙傛暟璁惧畾鍊间笉鑳藉ぇ浜�" + max + }) + return false + } + } + + return true; + }, + parataxis(rule_with_pre) { + let relation = ""; + this.VideoManageData.Dictionary.RULECOMPUTEBETWEEN.forEach(pre => { + if (pre.value === rule_with_pre) { + relation = pre.name; + } + }); + + return relation; + }, + + generatDescription() { + let desc = ""; + this.groupRules.forEach((r, index) => { + // console.log(r,index,'鎷兼帴') + if (index === 0) { + desc += + + r.sdkDesc + + r.argDesc + + r.operatorDesc + + r.valueDesc + + r.unit + } else { + desc += + ' ' + this.parataxis(r.rule_with_pre) + ' ' + + r.sdkDesc + + r.argDesc + + r.operatorDesc + + r.valueDesc + + r.unit + } + }); + // console.log(desc,'鎷兼帴') + return desc; + }, + createRule() { + if (!this.isTemplate && this.Cameras.length > 0) { + // 鏈�変腑鎽勫儚鏈烘垨鑰呮湭閫変腑鎽勫儚鏈轰换鍔★紝涓嶆墽琛屽垱寤� + if (!this.Cameras[0].cameraId) + return false; + } + + if (this.isLinkRule && this.TreeDataPool.selectedNodes.length < 2) { + this.$notify({ + type: "warning", + message: "璇烽�夋嫨鑷冲皯2涓憚鍍忔満!" + }) + return false; + } + + this.group_id = ""; + + this.addRule(0); + }, + cleanRule() { + this.groupRules.splice(0, this.groupRules.length); + }, + addRule(index) { + let newRule = JSON.parse(JSON.stringify(this.baseRule)); + newRule.sdksOptions = this.includeSdks; + if (!this.isLinkRule) { + // 璁剧疆榛樿鍏ㄩ儴鍖哄煙 + // if (!this.isTemplate) { + // newRule.polygonObj = this.allPolygonData[0]; + // this.selectPolygonOption(newRule) + // } + + // 璁剧疆绠楁硶 + // newRule.sdksOptions = this.includeSdks; + // 璁剧疆榛樿绠楁硶 + // newRule.sdkObj = newRule.sdksOptions[0] + // this.selectSDKOption(newRule, false) + + // newRule.sdk_arg_type = "target" + // this.selectArgTypeOption(newRule, true) + } + + // this.groupRules.push(newRule); + // 鎻掑叆鍒版寚瀹氫綅缃� + this.groupRules.splice(index + 1, 0, newRule); + }, + editHandle(ruleTxt) { + if (ruleTxt.length < 1) { + return; + } + let ruleInfo = JSON.parse(ruleTxt); + this.editRule(ruleInfo) + // 濡傛灉鏄仈鍔ㄤ换鍔�, 鏌ヨ鑱斿姩鎽勫儚鏈哄垪琛�, 灏嗘爲閫変腑鐨勫垪琛ㄦ洿鏀逛负璇ユ潯瑙勫垯鎵�闇�瑕佺殑鎽勫儚鏈�, 骞跺浠藉綋鍓嶇殑閫変腑鐘舵��, 瑙勫垯淇濆瓨鍚庢仮澶� + // if (this.isLinkRule) { + // this.VideoRuleData.treeSelectedNodesBackupOnEditLinkRule = [...this.TreeDataPool.selectedNodes] + // this.VideoRuleData.editLinkRuleRow = { ...ruleInfo } + + // this.TreeDataPool.selectedNodes = ruleInfo.group_rules.map(r => { + // return r.camera_id + // }) + // this.$nextTick(() => { + // setTimeout(() => { + // this.editRule(ruleInfo) + // }, 1000) + // }) + // } else { + // this.editRule(ruleInfo) + // } + }, + editRule(ruleGroup) { + this.group_id = ""; + + ruleGroup.forEach(rule => { + if (rule.group_id && rule.group_id != "") { + this.group_id = rule.group_id; + } + + // 濉厖鍖哄煙閫夐」鍒楄〃 + this.allPolygonData.forEach(p => { + if (p.polygonId === rule.polygon_id) { + rule.polygonObj = p; + } + }); + + if (!rule.polygonObj) { + rule.polygonObj = { + cameraId: rule.camera_id, + defence_state: 1, + name: "鏈煡鍖哄煙", + polygonId: rule.polygon_id, + } + } + + // 璁剧疆鍖哄煙 + this.selectPolygonOption(rule); + + // 璁剧疆绠楁硶缁� + this.setSdksOptions(rule); + + // 濉厖绠楁硶閫夐」鍒楄〃 + if (rule.sdksOptions) { + rule.sdksOptions.forEach(s => { + if (s.id === rule.sdk_id) { + rule.sdkObj = s; + } + }); + } + if (!rule.sdkObj || Object.keys(rule.sdkObj).length === 0) { + rule.sdkObj = { + id: rule.sdk_id, + sdk_name: "(宸插垹闄�)", + args: [], + delete: true + } + rule.sdksOptions.push(rule.sdkObj) + } + + this.selectSDKOption(rule, false); + // 瑙勫垯淇濆瓨鏃舵暟鎹簱涓嶅瓨鍙傛暟绫诲瀷锛岄渶瑕佹牴鎹�煎弽鏌� + // rule.sdk_arg_type = "" + // if (rule.sdk_arg_alias === "time_rule") { + // rule.sdk_arg_type = "target" + // } + rule.sdk_arg_type = "target" + // rule.sdkObj.args.forEach(ele => { + // if (ele.alias === rule.sdk_arg_alias) { + // rule.sdk_arg_type = ele.arg_type + // } + // }); + this.selectArgTypeOption(rule, false) + + if (rule.argsOptions) { + rule.argsOptions.forEach(arg => { + if (arg.alias === rule.sdk_arg_alias) { + rule.argObj = arg; + } + }); + this.selectArgsOption(rule, false); + } + + this.VideoManageData.Dictionary.RULECOMPUTE.forEach(opt => { + if (opt.value == rule.operator) { + rule.operatorObj = opt; + } + }); + + this.setOperator(rule); + this.selectValueOption(rule); + + if (rule.operator_type == "option") { + rule.valueOptions.forEach(val => { + if (val.value === rule.sdk_arg_value) { + rule.valueObj = val; + } + }); + } + if (!rule.valueObj) { + rule.valueObj = { + name: rule.sdk_arg_value, + value: rule.sdk_arg_value + } + } + this.setValue(rule); + }); + this.$nextTick(() => { + this.groupRules = ruleGroup; + }); + }, + delRule(rule) { + this.$confirm("鎻愮ず锛氬垹闄ゅ悗锛岃鏉¤鍒欏皢澶辨晥锛屾槸鍚﹀垹闄わ紵", { + center: true, + cancelButtonClass: "comfirm-class-cancle", + confirmButtonClass: "comfirm-class-sure" + }) + .then(() => { + deleteCameraRules({ groupId: rule.group_id }).then(res => { + if (res && res.success) { + this.$notify({ + type: "success", + message: "鍒犻櫎鎴愬姛" + }); + this.$emit("delete-rule"); + } else { + this.$notify({ + type: "error", + message: "鍒犻櫎澶辫触锛�" + }); + } + }); + }) + .catch(() => { }); + }, + submitRule() { + let groupRule = {}; + let group_text = ""; + + if (this.isTemplate) { + groupRule.rules = this.groupRules.map(r => { + return { + sdk_id: r.sdk_id, + sdk_arg_alias: r.sdk_arg_alias, + operator: r.operator, + operator_type: r.operator_type, + sdk_arg_value: r.sdk_arg_value, + sort: 1, + rule_with_pre: r.rule_with_pre + }; + }) + } else { + groupRule.rules = this.groupRules.map(r => { + return { + camera_id: r.camera_id, + group_id: r.group_id, + id: r.id, + operator: r.operator, + operator_type: r.operator_type, + polygon_id: r.polygon_id, + rule_with_pre: r.rule_with_pre, + sdk_arg_alias: r.sdk_arg_alias, + sdk_arg_value: r.sdk_arg_value, + sdk_id: r.sdk_id, + }; + }) + } + + groupRule.text = this.generatDescription(); + groupRule.id = this.group_id; + return groupRule; + + // 鏆傛椂鍏堜笉楠岃瘉 + for (let i in this.groupRules) { + let rule = this.groupRules[i] + if (!rule.polygon_id || !rule.sdk_id || !rule.operator || !rule.operator_type || rule.sdk_arg_type == "") { + this.$notify({ + type: "error", + message: "涓嶅厑璁搁厤缃笉瀹屾暣鐨勮鍒欙紝璇锋鏌ユ槸鍚︽湁鏈�夋嫨椤�" + }) + return; + } + if (!this.valideArgValue(rule)) { + return; + } + } + + if (this.isLinkRule) { + // 鍒ゆ柇瑙勫垯涓嚦灏戝寘鍚袱鎽勫儚鏈� + let cameraIds = Array.from(new Set(this.groupRules.map(r => { + return r.camera_id + }))) + if (cameraIds.length < 2) { + this.$notify({ + type: "error", + message: "闇�瑕�2涓笉鍚屾憚鍍忔満鎵嶈兘缁勬垚鑱斿姩瑙勫垯" + }) + return + } + + // 鑱斿姩瑙勫垯缂栬緫鍚庯紝鎭㈠涔嬪墠閫変腑鐨勬憚鍍忔満 + // if (this.VideoRuleData.treeSelectedNodesBackupOnEditLinkRule.length) { + // this.TreeDataPool.selectedNodes = this.VideoRuleData.treeSelectedNodesBackupOnEditLinkRule + // this.VideoRuleData.treeSelectedNodesBackupOnEditLinkRule = [] + // } + } + + this.onSubmitRule(payload); + } + } +}; +</script> + +<style lang="scss"> +.edit-rules-box { + width: 100%; + padding: 0px; + box-sizing: border-box; + .sub-task-rules-box { + width: 100%; + min-height: 50px; + border-top: 1px solid #eee; + padding-top: 7px; + + box-sizing: border-box; + padding-bottom: 38px; + .task-rules-button { + text-align: right; + margin: 15px; + } + + .el-select { + margin: 3px 8px; + min-width: 130px; + width: 12%; + } + } + + .el-button--text { + text-decoration: unset; + } + + p { + text-align: left; + // padding: 10px; + box-sizing: border-box; + } + + .task-blank { + float: left; + font-family: PingFangSC-Regular; + font-size: 12px; + color: #cccccc; + margin-top: 5px; + } + + .btn { + cursor: pointer; + color: #3d68e1; + margin-left: 10px; + font-size: 14px; + } +} +</style> \ No newline at end of file diff --git a/src/components/subComponents/VueCron.vue b/src/components/subComponents/VueCron.vue new file mode 100644 index 0000000..d5d59a0 --- /dev/null +++ b/src/components/subComponents/VueCron.vue @@ -0,0 +1,194 @@ +<template> + <div> + <b style="padding-right:30px;">瀹氭椂閲嶅惎:</b> + <el-select v-model="every" placeholder="璇烽�夋嫨" size="small" @change="changeEvery"> + <el-option label="鍏抽棴" value="never"></el-option> + <el-option label="姣忓ぉ" value="day"></el-option> + <el-option label="姣忓懆" value="week"></el-option> + <el-option label="姣忔湀" value="month"></el-option> + </el-select> + + <el-select + v-show="every == 'month'" + v-model="cronValueObj.day" + placeholder="璇烽�夋嫨" + size="small" + style="margin-left: 20px" + @change="updateExpression" + > + <el-option v-for="item in days" :key="item.value" :label="item.label" :value="item.value"></el-option> + </el-select> + + <el-select + v-show="every == 'week'" + v-model="cronValueObj.week" + placeholder="璇烽�夋嫨" + size="small" + style="margin-left: 20px" + @change="updateExpression" + > + <el-option label="鏄熸湡涓�" value="1"></el-option> + <el-option label="鏄熸湡浜�" value="2"></el-option> + <el-option label="鏄熸湡涓�" value="3"></el-option> + <el-option label="鏄熸湡鍥�" value="4"></el-option> + <el-option label="鏄熸湡浜�" value="5"></el-option> + <el-option label="鏄熸湡鍏�" value="6"></el-option> + <el-option label="鏄熸湡鏃�" value="7"></el-option> + </el-select> + + <el-time-picker + v-show="every !== 'never'" + v-model="time" + :picker-options="{selectableRange: '00:00:00 - 23:59:59'}" + value-format="HH:mm" + format="HH:mm" + placeholder="浠绘剰鏃堕棿鐐�" + size="small" + style="margin-left: 20px" + @change="updateExpression" + ></el-time-picker> + + <el-button + v-show="saveBtn" + type="primary" + size="small" + style="margin-left: 20px" + @click="save" + >淇濆瓨</el-button> + </div> +</template> + +<script> +export default { + name: "VueCrontab", + props: ["expression"], + computed: { + days: () => { + let arr = [] + for (let i = 1; i < 32; i++) { + arr.push({ + label: i + "鏃�", + value: i + "" + }) + } + + return arr + } + }, + watch: { + expression: function () { + this.resolveExp() + } + }, + data() { + return { + saveBtn: false, + every: "never", + time: "", + cronValueObj: { + min: "*", + hour: "*", + day: "*", + month: "*", + week: "*" + }, + cronText: "" + } + }, + mounted() { + this.resolveExp() + }, + methods: { + resolveExp() { + //鍙嶈В鏋� 琛ㄨ揪寮� + "鍑嗗鍙嶈В鏋�", this.expression; + if (this.expression.length) { + let arr = this.expression.split(" "); + if (arr.length >= 5) { + //6 浣嶄互涓婃槸鍚堟硶琛ㄨ揪寮� + this.cronValueObj.min = arr[0] + this.cronValueObj.hour = arr[1] + this.cronValueObj.day = arr[2] + // this.cronValueObj.month = arr[3], + this.cronValueObj.month = "*" + this.cronValueObj.week = arr[4] + } + + if (this.cronValueObj.week != "*") { + this.every = "week" + } else if (this.cronValueObj.day != "*") { + this.every = "month" + } else { + this.every = "day" + } + this.time = this.cronValueObj.hour + ":" + this.cronValueObj.min + } else { + //娌℃湁浼犲叆鐨勮〃杈惧紡 鍒欒繕鍘� + this.clearCron(); + } + }, + changeEvery() { + this.saveBtn = true; + if (this.every === "never") { + this.cronText = "" + return + } + if (this.every === "month") { + this.cronValueObj.week = "*" + this.cronValueObj.day = "1" + if (!this.time.length) { + this.time = "00:00" + } + } + if (this.every === "week") { + this.cronValueObj.day = "*" + this.cronValueObj.week = "1" + if (!this.time.length) { + this.time = "00:00" + } + } + if (this.every === "day") { + this.cronValueObj.day = "*" + this.cronValueObj.week = "*" + } + this.updateExpression() + }, + updateExpression() { + this.saveBtn = true; + if (this.time.length) { + let arr = this.time.split(":"); + this.cronValueObj.hour = arr[0] + this.cronValueObj.min = arr[1] + } + this.crontabValueString() + }, + clearCron() { + this.cronValueObj.second = "*" + this.cronValueObj.min = "*" + this.cronValueObj.hour = "*" + this.cronValueObj.day = "*" + this.cronValueObj.month = "*" + this.cronValueObj.week = "*" + }, + crontabValueString: function () { + let obj = this.cronValueObj; + this.cronText = + obj.min + + " " + + obj.hour + + " " + + obj.day + + " " + + obj.month + + " " + + obj.week + }, + save() { + this.$emit("update", this.cronText) + } + } +} +</script> + +<style lang="scss"> +</style> \ No newline at end of file diff --git a/src/components/subComponents/chartLiquid.vue b/src/components/subComponents/chartLiquid.vue new file mode 100644 index 0000000..4d7cdf5 --- /dev/null +++ b/src/components/subComponents/chartLiquid.vue @@ -0,0 +1,141 @@ +<template> + <div ref="ball" :style="{width: size + 'px', height: size + 'px', marginLeft: '10px'}"></div> +</template> + +<script> +import echarts from "echarts"; +import echartsLiquidfill from "echarts-liquidfill"; + +export default { + name: "EchartsLiquidFill", + props: { + title: { + type: String, + defalut: "" + }, + value: { + type: Number, + defalut: 0 + }, + size: { + type: Number, + defalut: 100 + } + }, + computed: { + fillColor() { + if (this.PollData.Thresholds.length > 0) { + for (let i = 0; i < this.PollData.Thresholds.length; i++) { + if (this.value <= this.PollData.Thresholds[i].Value) { + return this.PollData.Thresholds[i].Color; + } + } + } + + if (this.value <= 60) { + return "#13ce66" + } else if (this.value > 60 && this.value <= 80) { + return "#FF9C4A" + } else if (this.value > 80 && this.value <= 95) { + return "#f53d3d" + } else { + return "#5d0000" + } + } + }, + mounted() { + this.initChart() + }, + watch: { + value: function (newVal, oldVal) { + if (newVal !== oldVal) { + this.initChart() + } + } + }, + methods: { + initChart() { + let options = { + title: { + // 鏍囬 + text: this.title, + textStyle: { + // 鏍囬鐨勬牱寮� + color: "#222", // 瀛椾綋棰滆壊 + fontFamily: "Microsoft YaHei", // 瀛椾綋 + fontSize: 14, + fontWeight: "800", + align: "center", // 鏂囧瓧鐨勬按骞虫柟寮� + baseline: "middle", + position: "inside", + verticalAlign: "middle" // 鏂囧瓧鐨勫瀭鐩存柟寮� + }, + left: "center", // 瀹氫綅 + top: "14%" + }, + + grid: { + left: 50, + }, + series: [ + { + type: "liquidFill", + radius: "95%", + waveAnimation: true, + data: [ + { + value: this.value / 100, + direction: "left", + itemStyle: { + normal: { + color: this.fillColor + } + } + } + ], + outline: { + // show: true , //鏄惁鏄剧ず杞粨 甯冨皵鍊� + borderDistance: 1, // 澶栭儴杞粨涓庡浘琛ㄧ殑璺濈 鏁板瓧 + itemStyle: { + borderColor: this.fillColor, // 杈规鐨勯鑹� + borderWidth: 3, // 杈规鐨勫搴� + shadowBlur: 1, //澶栭儴杞粨鐨勯槾褰辫寖鍥� 涓�鏃﹁缃簡鍐呭閮芥湁闃村奖 + shadowColor: '#fff' //澶栭儴杞粨鐨勯槾褰遍鑹� + } + }, + itemStyle: { + opacity: 0.9, // 娉㈡氮鐨勯�忔槑搴� + shadowBlur: 0 // 娉㈡氮鐨勯槾褰辫寖鍥� + }, + backgroundStyle: { + color: "#fff" // 鍥捐〃鐨勮儗鏅鑹� + }, + label: { + // 鏁版嵁灞曠ず鏍峰紡 + show: true, + color: "#000", + insideColor: "#fff", + fontSize: 14, + fontWeight: 400, + align: "center", + baseline: "middle", + position: "inside", + normal: { + formatter: (this.value).toFixed(2) + '%', + textStyle: { + fontSize: 14, + fontWeight: 400, + color: "#000", + } + } + } + + } + ] + } + let chart = echarts.init(this.$refs.ball); + chart.setOption(options); + } + } +}; +</script> \ No newline at end of file diff --git a/src/components/subComponents/eChartsBar.vue b/src/components/subComponents/eChartsBar.vue new file mode 100644 index 0000000..4cd7a99 --- /dev/null +++ b/src/components/subComponents/eChartsBar.vue @@ -0,0 +1,174 @@ +<template> + <div ref="cpuMenery" style="height:100%;"></div> +</template> + +<script> +import echarts from "echarts"; + +export default { + name: "eChartsCpu", + props: { + title: { + type: String, + defalut: "" + }, + value: { + type: Number, + defalut: 0 + }, + yAxisData: { + type: Array, + default: () => { + return ["纭洏", "CPU", "绠楀姏", "鍐呭瓨"] + } + }, + xAxisData: { + type: Array, + default: () => { + return [] + } + }, + width: { + type: Number, + default: 500 + }, + size: { + type: Number, + defalut: 145 + } + }, + computed: { + + }, + data() { + return { + eChartsObj: {} + } + }, + mounted() { + // console.log(this.$refs.cpuMenery.offsetWidth,'this.$refs.cpuMenery',this.$refs.cpuMenery.offsetHeight) + if (this.$refs.cpuMenery.offsetWidth && this.$refs.cpuMenery.offsetHeight) { + this.initChart() + } + window.addEventListener('resize', this.windowSizeChange) + }, + watch: { + value: function (newVal, oldVal) { + if (newVal !== oldVal) { + this.initChart() + } + } + }, + methods: { + initChart() { + let options = { + title: { + // 鏍囬 + text: this.title + }, + tooltip: { + formatter: (data) => { + return data.value + '%' + } + }, + grid: { + top: 10, + right: 30, + bottom: 20, + left: 40, + }, + xAxis: { + show: false, + type: 'value', + max: 100, + splitLine: { + show: false + }, + axisLine: { + lineStyle: { + color: '#dfe6ec' + } + }, + axisTick: { + lineStyle: { + color: '#606266' + } + }, + axisLabel: { + color: '#606266' + }, + }, + yAxis: { + show: true, + type: 'category', + data: this.yAxisData, + axisLabel: { + interval: 0, + rotate: 0 + }, + axisLine: { + show: false, + lineStyle: { + color: '#dfe6ec' + } + }, + axisTick: { + show: false, + lineStyle: { + color: '#606266' + } + }, + axisLabel: { + color: '#606266', + align: 'right' + }, + }, + series: [ + { + type: 'bar', + stack: 'chart', + z: 3, + itemStyle: { + normal: { + color: '#3D68E1' + }, + emphasis: { + color: '#3D68E1' + } + }, + data: this.xAxisData, + label: { + show: true, + position: 'right', + formatter: (data) => { + return data.value + '%' + } + }, + }, + { + type: 'bar', + stack: 'chart', + silent: true, + itemStyle: { + normal: { + color: 'rgb(248, 248, 248)' + } + }, + data: this.xAxisData.map(function (i) { + return 100 - i; + }), + barMaxWidth: 15 + } + ] + } + this.eChartsObj = echarts.init(this.$refs.cpuMenery); + this.eChartsObj.setOption(options); + }, + windowSizeChange() { + this.eChartsObj.resize(); + }, + } +}; +</script> +<style lang="scss"> +</style> \ No newline at end of file diff --git a/src/components/subComponents/imgDown.vue b/src/components/subComponents/imgDown.vue new file mode 100644 index 0000000..5b988c3 --- /dev/null +++ b/src/components/subComponents/imgDown.vue @@ -0,0 +1,93 @@ +<template> + <div class="imgBox"> + <img + :src="'/httpImage/'+url" + class="cursor-pointer" + v-if="isPreview" + preview + /> + <img + :src="'/httpImage/'+url" + v-if="!isPreview" + /> + <el-button class="btn" @click="downloadIamge('/httpImage/'+url)"> + <i class="iconfont iconxiazai"></i> + </el-button> + </div> +</template> +<script> +import axios from "axios" +export default { + props:{ + url: { + default: "", + type: String + }, + isPreview: { + default: true, + type: Boolean + } + }, + methods:{ + downloadIamge(url) { + axios({ + method: "get", + url: url, + responseType: 'blob' + }).then(res => { + if (res.status == 200) { + var a = document.createElement('a') + var strs = url.split('/') + var href = new Blob([res.data],{type: 'image/jpeg'}) + a.href = URL.createObjectURL(href); + a.download = strs[strs.length - 1]+'.jpg' + a.click() + } + }).catch(err => { + this.$notify({ + type: "error", + message: "涓嬭浇澶辫触锛�"+err+"璇烽噸璇曪紒", + }) + }) + }, + } + +} +</script> +<style lang="scss" scoped> +.imgBox{ + width: 100%; + height: 100%; + position: relative; + img { + width: 100%; + height: 100%; + object-fit: contain + } + .btn { + width: 30px; + height: 30px; + position: absolute; + padding: 0; + right: 20%; + opacity: 1; + bottom: 10px; + -webkit-animation: fadenum 0.7s ease; + display: none; + i { + font-size: 20px + } + } +} +.imgBox:hover .btn { + display: inline; +} +@-webkit-keyframes fadenum{ /*璁剧疆鍐呭鐢辨樉绀哄彉涓洪殣钘�*/ + + 0%{opacity: 0;} + + 100%{opacity: 1;} + +} + +</style> \ No newline at end of file diff --git a/src/pages/algorithmManage/index/App.vue b/src/pages/algorithmManage/index/App.vue new file mode 100644 index 0000000..34488d2 --- /dev/null +++ b/src/pages/algorithmManage/index/App.vue @@ -0,0 +1,861 @@ +<template> + <div class="s-task-manage"> + <div style="height:100%;"> + <div class="flex-box task-manage"> + <div class="installModel" v-if="isInstall"> + <div class="progress-bar"> + <div class="inner-bar"></div> + </div> + </div> + <!-- 瓒呯骇绠$悊鍛樺彲瑙� --> + <div class="super" v-if="isSuperUser"> + <div class="left-box"> + <!-- <div class="title"> + <label>绠楁硶搴�</label> + </div>--> + <el-tabs + v-model="activeName" + type="border-card" + @tab-click="handleTabClick" + style="height: calc(100% - 20px);" + > + <el-tab-pane label="鎴戠殑绠楁硶" name="myAlgorithm"> + <div class="width-new-line task-list" v-show="activeName === 'myAlgorithm'"> + <div class="flex-list"> + <!-- <draggable + :list="installedList" + :group="{ name: 'article', pull: 'clone', put: false }" + :sort="false" + @start="startRight" + @end="endLeft" + style="display:inline" + >--> + + <div class="wrap-box" v-for="item in ungradeList" :key="item.id"> + <div class="list-choose-item-left"> + <div class="mask"> + <el-button type="primary" class="bot-btn" @click="donwload(item)">鍗囩骇</el-button> + </div> + + <div class="list-complete-item-handle"> + <div class="svg-wrap"> + <svg class="icon" aria-hidden="true" style="font-size:7rem;"> + <use :xlink:href="`#${item.icon}`" /> + </svg> + </div> + <div class="alg-name"> + <div style="padding:0px 10px 0px 10px;"> + <span>{{ item.sdk_name }}</span> + </div> + </div> + </div> + </div> + </div> + <div class="wrap-box" v-for="(item) in installedList" :key="item.id"> + <div class="list-choose-item-left"> + <div class="mask" v-if="!item.isEdit"> + <el-button + @click="commandAlgLib(item)" + type="primary" + class="bot-btn" + >缂栬緫鍚嶇О</el-button> + </div> + <div class="list-complete-item-handle"> + <!-- <span :class="`iconfont ${item.icon}`" style="font-size:3rem;"></span> --> + <div class="svg-wrap"> + <svg class="icon" aria-hidden="true" style="font-size:7rem;"> + <use :xlink:href="`#${item.icon}`" /> + </svg> + </div> + <div class="alg-name"> + <div style="padding:0px 10px 0px 10px;"> + <span v-if="!item.isEdit">{{ item.sdk_name }}</span> + + <el-input + size="small" + v-model="item.sdk_name" + v-if="item.isEdit" + v-focus + :maxlength="15" + @blur="inputBlur(item)" + ></el-input> + </div> + </div> + </div> + </div> + </div> + <!-- </draggable> --> + <div class="wrap-box" v-for="(item) in notInstalledList" :key="item.id"> + <div + class="list-choose-item-left list-choose-item-left-uninstal" + v-loading="downloading && downloadItem == item.id" + > + <div class="mask"> + <el-button type="primary" class="bot-btn" @click="donwload(item)">瀹夎</el-button> + </div> + <div class="click-download" title="涓嬭浇"> + <span class="iconfont iconxiazai1"></span> + </div> + <div class="list-complete-item-handle"> + <!-- <span :class="`iconfont ${item.icon}`" style="font-size:3rem;"></span> --> + <div class="svg-wrap"> + <svg class="icon" aria-hidden="true" style="font-size:7rem;"> + <use :xlink:href="`#${item.icon}`" /> + </svg> + </div> + <div class="alg-name"> + <div style="padding:0px 10px 0px 10px;"> + <span class="list-choose-item-left-uninstal">{{ item.sdk_name }}</span> + </div> + </div> + </div> + </div> + </div> + </div> + <!-- 鏈笅杞� --> + </div> + </el-tab-pane> + + <el-tab-pane + label="绂荤嚎鍗囩骇/瀹夎" + name="upgradeOrInstallation" + v-show="activeName==='upgradeOrInstallation'" + > + <div class="tab-content"> + <div class="action-bar"> + <file-uploader + single + tip + tipWords="涓婁紶绠楁硶" + uploadPlaceholder="绂荤嚎瀹夎绠楁硶" + url="/data/api-v/sdk/upload" + @complete="onFileUpload" + @file-added="onFileAdded" + /> + </div> + </div> + </el-tab-pane> + <el-tab-pane label="绠楁硶鍟嗗煄" name="algorithmMall" v-show="activeName==='algorithmMall'"> + <div class="tab-content"> + <div class="store-list"> + <div class="wrap-box"> + <div class="inner"> + <div class="mask" @click="actDrawerShow=true"> + <svg class="icon" aria-hidden="true" style="font-size:2rem;"> + <use xlink:href="#iconyunxiazai" /> + </svg> + </div> + <div class="alg-icon"> + <svg class="icon" aria-hidden="true" style="font-size:7rem;"> + <use xlink:href="#iconrenyuanyidong" /> + </svg> + </div> + <div class="alg-name">name</div> + </div> + </div> + </div> + </div> + <el-drawer title="涓嬭浇" :visible.sync="actDrawerShow" :direction="direction"> + <div class="drawer-content"> + <div class="current-step"> + <el-steps align-center :active="actStep" finish-status="success"> + <el-step title="娣诲姞婵�娲荤爜"></el-step> + <el-step title="婵�娲绘垚鍔�"></el-step> + </el-steps> + </div> + + <div v-if="actStep==0"> + <div class="act-code"> + <p>浣跨敤婵�娲荤爜灏嗘柊鐨勭畻娉曟坊鍔犲埌鎮ㄧ殑璐︽埛</p> + <el-input + v-model="activeCode" + placeholder="00000-00000-00000-00000-00000" + @blur="getCodeDetail" + ></el-input> + </div> + <div class="text-right"> + <el-button type="primary" @click="actived">婵�娲�</el-button> + </div> + </div> + <div v-else-if="actStep==1"> + <ul class="desc"> + <li> + <label>婵�娲荤爜:</label> + <span>YUAAA-AAAEU-QJQE3-ZRRXD-K9MWR</span> + </li> + <li> + <label>浜у搧鍚嶇О:</label> + <span>浜哄憳璺熻釜SDK</span> + </li> + <li> + <label>閰嶇疆璇︽儏:</label> + <span>鏃�</span> + </li> + <li> + <label>鏈嶅姟鍒版湡鏃�:</label> + <span>2021-03-04</span> + </li> + <li> + <label>璁稿彲璇�:</label> + <span>鏈澶�</span> + </li> + <li> + <label>璁惧ID:</label> + <span>3342-235f-ret55-fdsg</span> + </li> + </ul> + <div class="text-right"> + <el-button type="primary" @click="checkMyAlgorith">纭畾</el-button> + <p class="tip">鎻愮ず锛氳鍦ㄢ�滄垜鐨勭畻娉曗�濅腑鏌ョ湅骞跺畨瑁呯畻娉�</p> + </div> + </div> + </div> + </el-drawer> + </el-tab-pane> + </el-tabs> + </div> + + <!-- 绠楁硶绠$悊 --> + <!-- <div class="right-box" style="width:58%"> + <div class="title"> + <label>绠楁硶绠$悊</label> + <el-button size="small" type="primary" @click="addTask" style="float:right">娣诲姞浠诲姟</el-button> + </div> + <div id="taskArea" class="width-new-line task-manage-table"> + <div + v-for="(row, Index) in TaskMange.list2" + :key="Index" + class="dic-border mb10 width-new-line" + > + <div class="flex-box" style="height:100%;"> + <div class="task-name-google"> + <div class="mask" v-if="!row.isSetting"> + <el-tooltip + content="缂栬緫鍚嶇О" + transition="none" + placement="left" + popper-class="atooltip" + > + <i + class="iconfont iconbianji1" + style="font-size:30px; left:14px; top:30px;" + @click="clickSet(row)" + ></i> + </el-tooltip> + <el-tooltip + content="鍒犻櫎浠诲姟" + transition="none" + placement="right" + popper-class="atooltip" + > + <i + class="iconfont iconshanchu4" + style="font-size:30px; color:red; top:30px; left:28px;" + @click="clickDel(row, Index)" + ></i> + </el-tooltip> + <el-tooltip + :content="`${row.enable ? '鍏抽棴浠诲姟' : '寮�鍚换鍔�'}`" + placement="left" + popper-class="atooltip" + transition="none" + style="left: -45px; top: 65px;" + > + <el-switch + :active-value="true" + :inactive-value="false" + v-model="row.enable" + @change="updateTaskStatus(row)" + ></el-switch> + </el-tooltip> + <el-tooltip + content="淇敼鍥炬爣" + transition="none" + placement="right" + popper-class="atooltip" + > + <i class="iconfont icontupian1" style="font-size:12px; left:-20px; top:65px;"></i> + </el-tooltip> + </div> + <div class="list-choose-header flex-center"> + <span class="iconfont iconrenwu" style="font-size:3rem;color:#fff;"></span> + </div> + <div class="task-name-div"> + <span :title="row.name" v-if="!row.isSetting">{{ row.name }}</span> + <el-input + size="small" + v-model="row.name" + v-if="row.isSetting" + v-focus + :maxlength="15" + style="width:120px" + @blur="updateTaskName(row)" + ></el-input> + </div> + </div> + + <div id="child" class="overflow-x"> + <draggable + :id="row.id" + :list="row.child" + group="article" + filter=".mask" + class="dragAreaR flex-box" + @start="startRight" + @end="endLeft" + > + <div + v-for="(item, index) in row.child" + :key="index" + :title="item.sdk_name" + :class=" + item.isSelect + ? 'list-choose-item alg-shadow' + : 'list-choose-item' + " + > + <div class="mask"> + <el-tooltip + content="璁剧疆" + transition="none" + placement="top" + popper-class="atooltip" + > + <i + class="iconfont iconshezhi" + style="font-size:15px; top:43px;" + @click="clickSetAlgo(row, item)" + ></i> + </el-tooltip> + <el-tooltip + content="鍒犻櫎绠楁硶" + transition="none" + placement="top" + popper-class="atooltip" + > + <i + class="iconfont iconshanchu4" + style="font-size: 30px; color:red; left:12px;" + @click="clickDelSdk(row, item)" + ></i> + </el-tooltip> + </div> + <div class style="height:100%;padding: 20px 10px 10px 10px;"> + <div class="flex-center" style> + <span + :class="`iconfont ${item.icon}`" + style="font-size:3rem;margin-left:5px;" + ></span> + </div> + <div + :class="item.isSelect?'select-color text-css':'task-name text-css'" + style + >{{ item.sdk_name }}</div> + </div> + </div> + <div style class="tc drag-info flex-center"> + <div class="drag-info-text"> + <span>鎷栧姩绠楁硶鍥炬爣鍒拌繖閲�</span> + </div> + </div> + </draggable> + </div> + </div> + + <div class v-if="row.isShowSetAlgo"> + <div class="b-top"> + <div class="flex-box mt10"> + <span class="alg-t ml10 mr10 fb">绠楁硶閰嶇疆</span> + </div> + <div style="border: 1px solid #EBEBEB;"></div> + <div> + <div class="p5"> + <div v-for="(temp, index) in TaskMange.argsList" :key="index" class="p5 ml50"> + <el-row :gutter="2"> + <el-col :span="4"> + <el-select + v-model="temp.value1" + placeholder="璇烽�夋嫨" + width="200px" + disabled + @change="selectChange($event, 'options1', temp)" + > + <el-option + v-for="item in temp.options1" + :key="item.id" + :label="item.name" + :value="item.value" + ></el-option> + </el-select> + </el-col> + <el-col :span="4"> + <el-select + v-model="temp.value2" + placeholder="璇烽�夋嫨" + @change="selectChange($event, 'options2', temp)" + > + <el-option + v-for="item in temp.options2" + :key="item.id" + :label="item.name" + :value="item.value" + ></el-option> + </el-select> + </el-col> + <el-col :span="12"> + <div v-if="temp.value2 === 'is'"> + <el-select + v-model="temp.value3" + placeholder="璇烽�夋嫨" + @change="selectChange($event, 'options3', temp)" + > + <el-option + v-for="item in temp.options3" + :key="item.id" + :label="item.name" + :value="item.value" + ></el-option> + </el-select> + </div> + <div v-else class="flex-row-left"> + <div> + <el-input + v-model="temp.value3" + placeholder="璇疯緭鍏�" + @blur="valiNum(temp.value3)" + ></el-input> + </div> + <div v-if="temp.unit" class="unit-class"> + <span>(鍗曚綅锛歿{ temp.unit }})</span> + </div> + </div> + </el-col> + </el-row> + </div> + </div> + </div> + <div class="flex-row-right" style="margin: 0px 25px 5px 0px;"> + <a + style="font-family: PingFangSC-Medium;line-height: 32px; + font-size: 13px;text-decoration:underline; + color: #3D68E1;margin-right: 28px;" + @click="getDefault" + >鎭㈠榛樿鍊�</a> + <el-button type="info" size="small" class="mb10" @click="cancle(row)">鍙栨秷</el-button> + <el-button type="primary" size="small" class="mr50 mb10" @click="save">淇濆瓨</el-button> + </div> + </div> + </div> + </div> + </div> + </div>--> + </div> + <!-- 涓�鑸敤鎴峰彲瑙� --> + <div class="common" v-if="!isSuperUser"> + <!-- 绠楁硶绠$悊 --> + <!-- <div class="right-box" style="width:84%;margin:auto 8%"> + <div class="title"> + <label>绠楁硶绠$悊</label> + <el-button + size="small" + type="primary" + @click="addTask" + style="float:right" + v-show="isSuperUser" + >娣诲姞浠诲姟</el-button> + </div> + <div id="taskArea" class="width-new-line task-manage-table"> + <div + v-for="(row, Index) in TaskMange.list2" + :key="Index" + class="dic-border mb10 width-new-line" + > + <div class="flex-box" style="height:100%;"> + <div class="task-name-google"> + <div class="mask" v-if="row.isSetting"> + <el-tooltip + content="缂栬緫鍚嶇О" + transition="none" + placement="left" + popper-class="atooltip" + > + <i + class="iconfont iconbianji1" + style="font-size:30px; left:14px; top:30px;" + @click="clickSet(row)" + ></i> + </el-tooltip> + <el-tooltip + content="鍒犻櫎浠诲姟" + transition="none" + placement="right" + popper-class="atooltip" + > + <i + class="iconfont iconshanchu4" + style="font-size:30px; color:red; top:30px; left:28px;" + @click="clickDel(row, Index)" + ></i> + </el-tooltip> + <el-tooltip + :content="`${row.enable ? '鍏抽棴浠诲姟' : '寮�鍚换鍔�'}`" + placement="left" + popper-class="atooltip" + transition="none" + style="left: -45px; top: 65px;" + > + <el-switch + :active-value="true" + :inactive-value="false" + v-model="row.enable" + @change="updateTaskStatus(row)" + ></el-switch> + </el-tooltip> + <el-tooltip + content="淇敼鍥炬爣" + transition="none" + placement="right" + popper-class="atooltip" + > + <i + class="iconfont icontupian1" + style="font-size:12px; left:-20px; top:65px;" + ></i> + </el-tooltip> + </div> + <div class="list-choose-header flex-center"> + <span class="iconfont iconrenwu" style="font-size:3rem;color:#fff;"></span> + </div> + <div class="task-name-div"> + <span :title="row.name" v-if="!row.isSetting">{{ row.name }}</span> + <el-input + size="small" + v-model="row.name" + v-if="row.isSetting" + v-focus + :maxlength="15" + style="width:120px" + @blur="updateTaskName(row)" + ></el-input> + </div> + </div> + + <div id="child" class="overflow-x"> + <div + :id="row.id" + :list="row.child" + group="article" + filter=".child" + class="dragAreaR flex-box" + @start="startRight" + @end="endLeft" + > + <div + v-for="(item, index) in row.child" + :key="index" + :title="item.sdk_name" + :class=" + item.isSelect + ? 'list-choose-item alg-shadow' + : 'list-choose-item' + " + > + <div class="mask"> + <el-tooltip + content="璁剧疆" + transition="none" + placement="top" + popper-class="atooltip" + > + <i + class="iconfont iconshezhi" + style="font-size:15px; top:43px;" + @click="clickSetAlgo(row, item)" + ></i> + </el-tooltip> + <el-tooltip + content="鍒犻櫎绠楁硶" + transition="none" + placement="top" + popper-class="atooltip" + v-show="isSuperUser" + > + <i + class="iconfont iconshanchu4" + style="font-size: 30px; color:red; left:12px;" + @click="clickDelSdk(row, item)" + ></i> + </el-tooltip> + </div> + <div class style="height:100%;padding: 20px 10px 10px 10px;"> + <div class="flex-center" style> + <span + :class="`iconfont ${item.icon}`" + style="font-size:3rem;margin-left:5px;" + ></span> + </div> + <div + :class="item.isSelect?'select-color text-css':'task-name text-css'" + style + >{{ item.sdk_name }}</div> + </div> + </div> + <div style class="tc drag-info flex-center" v-show="isSuperUser"> + <div class="drag-info-text"> + <span>鎷栧姩绠楁硶鍥炬爣鍒拌繖閲�</span> + </div> + </div> + </div> + </div> + </div> + + <div class v-if="row.isShowSetAlgo"> + <div class="b-top"> + <div class="flex-box mt10"> + <span class="alg-t ml10 mr10 fb">绠楁硶閰嶇疆</span> + </div> + <div style="border: 1px solid #EBEBEB;"></div> + <div> + <div class="p5"> + <div + v-for="(temp, index) in TaskMange.argsList" + :key="index" + class="p5 ml50" + > + <el-row :gutter="2"> + <el-col :span="4"> + <el-select + v-model="temp.value1" + placeholder="璇烽�夋嫨" + width="200px" + disabled + @change="selectChange($event, 'options1', temp)" + > + <el-option + v-for="item in temp.options1" + :key="item.id" + :label="item.name" + :value="item.value" + ></el-option> + </el-select> + </el-col> + <el-col :span="4"> + <el-select + v-model="temp.value2" + placeholder="璇烽�夋嫨" + disabled + @change="selectChange($event, 'options2', temp)" + > + <el-option + v-for="item in temp.options2" + :key="item.id" + :label="item.name" + :value="item.value" + ></el-option> + </el-select> + </el-col> + <el-col :span="12"> + <div v-if="temp.value2 === 'is'"> + <el-select + v-model="temp.value3" + placeholder="璇烽�夋嫨" + @change="selectChange($event, 'options3', temp)" + > + <el-option + v-for="item in temp.options3" + :key="item.id" + :label="item.name" + :value="item.value" + ></el-option> + </el-select> + </div> + <div v-else class="flex-row-left"> + <div> + <el-input + v-model="temp.value3" + placeholder="璇疯緭鍏�" + :disabled="temp.value1 !== 'score'" + @blur="valiNum(temp.value3)" + ></el-input> + </div> + <div v-if="temp.unit" class="unit-class"> + <span>(鍗曚綅锛歿{ temp.unit }})</span> + </div> + </div> + </el-col> + </el-row> + </div> + </div> + </div> + <div class="flex-row-right" style="margin: 0px 25px 5px 0px;"> + <a + style="font-family: PingFangSC-Medium;line-height: 32px; + font-size: 13px;text-decoration:underline; + color: #3D68E1;margin-right: 28px;" + @click="getDefault" + v-show="isSuperUser" + >鎭㈠榛樿鍊�</a> + <el-button type="info" size="small" class="mb10" @click="cancle(row)">鍙栨秷</el-button> + <el-button type="primary" size="small" class="mr50 mb10" @click="save">淇濆瓨</el-button> + </div> + </div> + </div> + </div> + </div> + </div> --> + </div> + </div> + </div> + </div> +</template> +<script> + +import { + findAllSdk, + findAll, + addTaskSdk, + delTaskSdk, + deleteTask, + updateTaskStatus, + updateTaskName, + getSdkArgs, + saveTaskSdkRule, + addTask, + getRulesByTaskSdk, + deleteTaskSdkRule, + findByType, + getTagList, + downloadSdk, + installSdk +} from "./api"; +import FileUploader from "@/components/subComponents/FileUpload/index"; + +export default { + name: "algorithmManage", + props: {}, + components: { + FileUploader + }, + + data() { + return { + activeName: "myAlgorithm", + patchUpdateStatus: "", + dragging: false, + list1: [ + { + sdk_name: "浜鸿劯鎻愬彇" + } + ], + list2: [ + { + id: "001", + name: "浠诲姟1", + child: [ + { + id: "1", + sdk_name: "浜鸿劯妫�娴�", + isSelect: false + }, + { + id: "2", + sdk_name: "浜鸿劯瀵规瘮", + isSelect: false + } + ], + isSetting: false, + isShowSetAlgo: false + } + ], + argsList: [], + baseObject: { + id: "", + algoId: "", + options1: [], + options2: [], + options3: [], + value1: "", + value2: "", + value3: "", + unit: "" + }, + currentAlgoId: "", + currentTaskId: "", + isSuperUser: false, + downloadItem: "", + downloading: false, + sceneDialogVisible: false, + dialogTitle: '', + direction: "rtl", + actDrawerShow: false, + actStep: 0, + activeCode: "", + sceneTemplates: [], + appSceneForm: { + id: "", + name: "", + desc: "", + rules: "", + txt: "" + }, + sceneSdks: [], + sceneRuleList: "", + isInstall: false, + installPercentage: 0 + } + }, + methods: {}, + mounted() {} +}; +</script> +<style lang="scss"> +.s-task-manage { + width: 100% !important; + height: 100%; + + box-sizing: border-box; + background-color: rgb(233, 235, 242); + padding: 10px; + text-align: left; + // background-color: #f2f6fc; + .s-video-manage-breadcrumb { + height: 5%; + -webkit-box-sizing: border-box; + border: 1px solid #e4e7ed; + background-color: rgb(255, 255, 255); + -webkit-box-shadow: #e4e7ed 0px 0px 9px inset; + box-shadow: #e4e7ed 0px 0px 9px inset; + border-radius: 5px; + } + .el-tabs { + height: calc(100% - 50px); + // margin-top: 5px !important; + } + .el-tabs--border-card > .el-tabs__header { + border: none; + } + .el-tabs__item.is-top { + height: 50px; + padding: 5px 50px !important; + font-size: 15px; + border: none !important; + } + .el-tabs__item.is-top.is-active { + font-weight: bold; + } + .el-tabs__content { + width: 100%; + height: calc(100% - 34px); + box-sizing: border-box; + } + .el-tab-pane { + width: 100%; + height: 100%; + } +} +.el-breadcrumb__inner { + font-weight: bold; + color: #606266; + cursor: pointer; +} +</style> diff --git a/src/pages/algorithmManage/index/api.ts b/src/pages/algorithmManage/index/api.ts new file mode 100644 index 0000000..64ecdad --- /dev/null +++ b/src/pages/algorithmManage/index/api.ts @@ -0,0 +1,145 @@ +import request from '@/scripts/httpRequest' +import qs from "qs"; + +// 鏌ヨ鎵�鏈夌畻娉� +export const findAllSdk = (query: any) => { + return request({ + url: "/data/api-v/sdk/findAllSdk", + method: "get", + params: query + }); +}; + +// 鏌ユ壘鎵�鏈変换鍔★紝鍖呭惈浠诲姟淇℃伅鍜屽搴旂殑绠楁硶淇℃伅 +export const findAll = (query: any) => { + return request({ + url: "/data/api-v/task/findAll", + method: "get", + params: query + }); +}; + +// 缁欎换鍔℃坊鍔犵畻娉� +export const addTaskSdk = (query: any) => { + return request({ + url: "/data/api-v/task/addTaskSdk", + method: "post", + data: query + }) +} + +// 缁欎换鍔″垹闄ょ畻娉� +export const delTaskSdk = (query: any) => { + return request({ + url: "/data/api-v/task/delTaskSdk", + method: 'get', + params: query + }) +} + +// 鍒犻櫎浠诲姟 +export const deleteTask = (query: any) => { + return request({ + url: '/data/api-v/task/delete', + method: 'get', + params: query + }) +} + +// 鏇存柊浠诲姟鐘舵�� +export const updateTaskStatus = (query: any) => { + return request({ + url: '/data/api-v/task/updateTaskStatus', + method: 'post', + data: query + }) +} + +// 鏇存柊浠诲姟鍚嶇О +export const updateTaskName = (query: any) => { + return request({ + url: '/data/api-v/task/updateTaskName', + method: 'post', + data: qs.stringify(query) + }) +} + +// 鑾峰彇绠楁硶鍙傛暟 +export const getSdkArgs = (query: any) => { + return request({ + url: '/data/api-v/sdkArg/getSdkArgs', + method: 'get', + params: query + }) +} + +// 绠楁硶鍙傛暟淇濆瓨 +export const saveTaskSdkRule = (query: any) => { + return request({ + url: '/data/api-v/task/saveTaskSdkRule', + method: 'post', + data: query + }) +} + +// 娣诲姞浠诲姟 +export const addTask = (query: any) => { + return request({ + url: '/data/api-v/task/addTask', + method: 'post', + data: query + }) +} + +// 鏌ヨ绠楁硶瑙勫垯 +export const getRulesByTaskSdk = (query: any) => { + return request({ + url: '/data/api-v/task/getRulesByTaskSdk', + method: 'get', + params: query + }) +} + +// 鎭㈠榛樿 +export const deleteTaskSdkRule = (query: any) => { + return request({ + url: '/data/api-v/task/deleteTaskSdkRule', + method: 'post', + data: qs.stringify(query) + }) +} + +// 鏍规嵁绫诲瀷鏌ユ壘瀛楀吀 +export const findByType = (query: any) => { + return request({ + url: '/data/api-v/dictionary/findByType', + method: "get", + params: query + }) +} + +// 鏌ヨ妫�绱㈡爣绛� +export const getTagList = (query: any) => { + return request({ + url: '/data/api-v/es/tagList', + method: 'post', + data: query + }) +} + +export const downloadSdk = (query: any) => { + return request({ + url: '/data/api-v/sdk/sdkDownload', + method: 'get', + params: query + }) +} + +//瀹夎宸蹭笂浼犵殑绠楁硶鎺ュ彛 +export const installSdk = (file: any) => { + return request({ + url: '/data/api-v/sdk/install', + method: 'post', + params: file + }) +} \ No newline at end of file diff --git a/src/pages/algorithmManage/index/main.ts b/src/pages/algorithmManage/index/main.ts new file mode 100644 index 0000000..264f7e4 --- /dev/null +++ b/src/pages/algorithmManage/index/main.ts @@ -0,0 +1,11 @@ +import Vue from 'vue' +import ElementUI from 'element-ui' +import 'element-ui/lib/theme-chalk/index.css' +import App from './App.vue' + +Vue.use(ElementUI) + +new Vue({ + el: '#app', + render: h => h(App) +}) diff --git a/src/pages/desktop/index/App.vue b/src/pages/desktop/index/App.vue index b58209a..aaa21d5 100644 --- a/src/pages/desktop/index/App.vue +++ b/src/pages/desktop/index/App.vue @@ -3,6 +3,7 @@ <tools></tools> <preference></preference> <desktop></desktop> + <tools-entry></tools-entry> <dock ref="dock_model"></dock> <notice-tip ref="notice_tip_model"></notice-tip> <notification-center></notification-center> @@ -16,12 +17,13 @@ import NotificationCenter from './components/NotificationCenter'; import NoticeTip from './components/NoticeTip'; import Tools from './components/Tools'; +import ToolsEntry from './components/ToolsEntry'; import axios from 'axios' export default { name: 'app', components: { - Desktop, Dock, Preference, NotificationCenter, NoticeTip, Tools + Desktop, Dock, Preference, NotificationCenter, NoticeTip, Tools, ToolsEntry }, mounted() { document.getElementById('app').style.backgroundImage = process.env.VUE_APP_MAIN_URL; @@ -113,6 +115,14 @@ width: 100%; height: 100%; background-size: 100% 100%; - background-image: url("../../../assets/img/desktop/main.jpg"); + background-image: url("../../../assets/img/desktop/desktop.png"); + background-attachment: fixed; +} + +.clearFix:after{ + content: ''; + display: block; + height: 0; + clear: both; } </style> diff --git a/src/pages/desktop/index/components/Dock.vue b/src/pages/desktop/index/components/Dock.vue index 4a6bcd3..68e3d4a 100644 --- a/src/pages/desktop/index/components/Dock.vue +++ b/src/pages/desktop/index/components/Dock.vue @@ -10,10 +10,10 @@ <span>{{dock.alt}}</span> <img class="dock-item" :src="dock.src" :alt="dock.alt" /> </a> - <img v-show="dock.isOpen" class="dock-item-dot" src="images/circle.png" /> + <img v-show="dock.isOpen" class="dock-item-dot" :src="`${publicPath}images/circle.png`" /> </div> <a class="dock-item-split"> - <img src="images/split.jpg" alt="split" /> + <img :src="`${publicPath}images/split.jpg`" alt="split" /> </a> <div v-for="dock in this.$store.state.desktop.minDocks" :key="dock.id" class="dock-item-wrap"> <a @click="dockClick(dock)"> @@ -24,7 +24,7 @@ <div class="dock-item-wrap"> <a> <span>trash</span> - <img class="dock-item" src="images/trash.png" alt="trash" /> + <img class="dock-item" :src="`${publicPath}images/trash.png`" alt="trash" /> </a> </div> </div> @@ -35,6 +35,14 @@ export default { name: "Dock", + data(){ + return { + publicPath: process.env.BASE_URL + } + }, + mounted(){ + console.log(this.publicPath) + }, methods: { getOffsetTop: function (el) { if (el.offsetParent == null) { diff --git a/src/pages/desktop/index/components/Tools.vue b/src/pages/desktop/index/components/Tools.vue index ea2a2b0..385e1d2 100644 --- a/src/pages/desktop/index/components/Tools.vue +++ b/src/pages/desktop/index/components/Tools.vue @@ -1,36 +1,53 @@ <template> <div class="tools"> - <div class="tools-left"> - <div - :class="['tools-icon', {clicked:this.$store.state.desktop.preferenceVisiable}]" - @click="togglePreference()" - > - <span class="fa fa-apple"></span> + <div class="center"> + <div class="tools-left"> + <div + :class="['tools-icon', {clicked:this.$store.state.desktop.preferenceVisiable}]" + @click="togglePreference()" + > + <img class="system" :src="`${publicPath}images/header-icon/system.png`" /> + <!-- <span class="fa fa-apple"></span> --> + </div> + <div class="tools-icon" @click="openSafari()"> + <!-- <span class="fa fa-safari"></span> --> + <img class="smart-ai" :src="`${publicPath}images/header-icon/SmartAI.png`" alt=""> + </div> </div> - <div class="tools-icon" @click="openSafari()"> - <span class="fa fa-safari"></span> - </div> - </div> - <div class="tools-middle"></div> - <div class="tools-right"> - <div class="tools-icon"> - <span class="fa fa-battery-full"></span> - </div> - <timer></timer> - <div class="tools-icon tools-notification-center" @click="notificationCenterClick()"> - <span - :class="['fa', {'fa-list-ul':notificationCenterNoMessage()}, {'fa-comment-o on-new-msg':!notificationCenterNoMessage()},{'fa-commenting-o':notificationCenterMessageFlicker()}]" - ></span> - </div> - <div class="tools-icon tools-show-desktop"> - <span> </span> + <div class="tools-middle"></div> + <div class="tools-right"> + <div class="tools-icon"> + <!-- <span class="fa fa-battery-full"></span> --> + <img :src="`${publicPath}images/header-icon/search.png`" alt=""> + </div> + <div class="tools-icon"> + <!-- <span class="fa fa-battery-full"></span> --> + <img :src="`${publicPath}images/header-icon/help.png`" alt=""> + </div> + <div class="tools-icon"> + <!-- <span class="fa fa-battery-full"></span> --> + <img :src="`${publicPath}images/header-icon/notice.png`" alt=""> + </div> + <div class="tools-icon"> + <!-- <span class="fa fa-battery-full"></span> --> + <img :src="`${publicPath}images/header-icon/user.png`" alt=""> + </div> + <!-- <timer></timer> --> + <div class="tools-icon tools-notification-center" @click="notificationCenterClick()"> + <span + :class="['fa', {'fa-list-ul':notificationCenterNoMessage()}, {'fa-comment-o on-new-msg':!notificationCenterNoMessage()},{'fa-commenting-o':notificationCenterMessageFlicker()}]" + ></span> + </div> + <div class="tools-icon tools-show-desktop"> + <span> </span> + </div> </div> </div> </div> </template> <script> -import Timer from './Timer'; +import Timer from "./Timer"; export default { name: "Tools", @@ -39,40 +56,47 @@ }, data() { return { + publicPath: process.env.BASE_URL, notificationCenterVisible: false, - notificationCenterMessageCount: 0, - } + notificationCenterMessageCount: 0 + }; }, created() { let _that = this; if (window.toolIntervalArr) { window.toolIntervalArr.forEach(item => clearInterval(item)); } - window.toolIntervalArr = [setInterval(function () { - _that.notificationCenterMessageCount += 1; - }, 600)]; + window.toolIntervalArr = [ + setInterval(function() { + _that.notificationCenterMessageCount += 1; + }, 600) + ]; }, methods: { - notificationCenterClick: function () { + notificationCenterClick: function() { this.notificationCenterVisible = !this.notificationCenterVisible; - this.$store.commit('desktop/changeNotificationCenterVisible', - this.notificationCenterVisible); + this.$store.commit( + "desktop/changeNotificationCenterVisible", + this.notificationCenterVisible + ); }, - notificationCenterNoMessage: function () { + notificationCenterNoMessage: function() { return this.$store.state.desktop.messageNotices.length === 0; }, - notificationCenterMessageFlicker: function () { - return ((this.notificationCenterMessageCount % 2) === 0) - && !this.notificationCenterNoMessage(); + notificationCenterMessageFlicker: function() { + return ( + this.notificationCenterMessageCount % 2 === 0 && + !this.notificationCenterNoMessage() + ); }, - openSafari: function () { + openSafari: function() { this.$store.commit("desktop/openSafari"); }, - togglePreference: function () { + togglePreference: function() { this.$store.commit("desktop/togglePreference"); } } -} +}; </script> <style scoped> @@ -80,31 +104,39 @@ width: 100%; position: fixed; top: 0; - height: 30px; - line-height: 30px; - background-color: rgba(15, 15, 0, 0.4); + height: 40px; + line-height: 40px; + background-color: #d9e5f1; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); z-index: 120; - color: #fff; + color: #000; } - +.tools .center { + width: 1300px; + height: 40px; + margin: auto; +} .tools .tools-left { width: 200px; height: 100%; float: left; margin-left: 8px; + } .tools-icon { text-align: center; - width: 30px; height: 100%; display: inline-block; + vertical-align: top; + line-height: 56px; + margin-right: 28px; } .tools .tools-icon:hover, .tools .tools-icon.clicked { color: white; - background-color: rgba(49, 156, 241, 0.71); + background-color: #98aabe; cursor: pointer; } diff --git a/src/pages/desktop/index/components/ToolsEntry.vue b/src/pages/desktop/index/components/ToolsEntry.vue new file mode 100644 index 0000000..adbba7c --- /dev/null +++ b/src/pages/desktop/index/components/ToolsEntry.vue @@ -0,0 +1,95 @@ +<template> + <div class="tools-entry"> + <div class="entry-wrap"> + <div class="app-list clearFix"> + <div class="app" v-for="(item,index) in applist" :key="index"> + <div class="wrap"> + <div class="app-icon"> + <img :src="item.src" alt=""> + </div> + <div class="app-name">{{item.name}}</div> + </div> + </div> + </div> + </div> + </div> +</template> + +<script> +export default { + name:'toolsEntry', + data(){ + return { + publicPath: process.env.BASE_URL, + applist:[ + {src: `/images/app-mid/camera-access.png`, name:'鎽勫儚鏈烘帴鍏�'}, + {src: `/images/app-mid/datastack-config.png`, name:'鏁版嵁鏍堥厤缃�'}, + {src: `/images/app-mid/DVR-access.png`, name:'纭洏褰曞儚鏈烘帴鍏�'}, + {src: `/images/app-mid/data-push.png`, name:'鏁版嵁鎺ㄩ��'}, + {src: `/images/app-mid/GB-config.png`, name:'GB28281閰嶇疆'}, + {src: `/images/app-mid/scene-config.png`, name:'鍦烘櫙閰嶇疆'}, + {src: `/images/app-mid/library.png`, name:'姣斿搴撶鐞�'}, + {src: `/images/app-mid/poll.png`, name:'杞绠$悊'}, + {src: `/images/app-mid/algorithm-manage.png`, name:'绠楁硶绠$悊'}, + {src: `/images/app-mid/algorithm-store.png`, name:'绠楁硶鍟嗗煄'}, + {src: `/images/app-mid/hashrate-manage.png`, name:'绠楀姏绠$悊'}, + {src: `/images/app-mid/monitor.png`, name:'瀹炴椂鐩戞帶-鍦ㄧ嚎鎾斁'}, + {src: `/images/app-mid/search.png`, name:'妫�绱�-缁熻鏌ヨ'}, + {src: `/images/app-mid/360.png`, name:'鍏ㄦ櫙瑙嗛'}, + {src: `/images/app-mid/log-manage.png`, name:'鏃ュ織绠$悊'}, + {src: `/images/app-mid/device.png`, name:'璁惧绠$悊'}, + {src: `/images/app-mid/settings.png`, name:'绯荤粺璁剧疆'}, + {src: `/images/app-mid/vindicate.png`, name:'绯荤粺缁存姢'} + ] + } + } +}; +</script> + +<style lang="scss"> + .tools-entry{ + //margin-top: 130px; + position: absolute; + top: 142px; + left: 50%; + transform: translateX(-50%); + .entry-wrap{ + width: 1180px; + padding: 0 60px; + margin: 0 auto; + .app-list{ + .app{ + width: 16.6%; + margin-bottom: 54px; + float: left; + .wrap{ + .app-icon{ + text-align: center; + line-height: 110px; + width: 110px; + height: 110px; + margin: auto; + img{ + vertical-align: middle; + margin-right: -3px; + } + } + .app-name{ + padding-top: 10px; + text-align: center; + font: Bold 16px/16px Microsoft JhengHei; + color: #fff; + } + } + + &:hover{ + .app-icon{ + background: rgba(0,0,0,.4); + } + } + + } + } + } + } +</style> \ No newline at end of file diff --git a/src/pages/desktop/index/mock/userData.json b/src/pages/desktop/index/mock/userData.json index 1260c13..c5040fd 100644 --- a/src/pages/desktop/index/mock/userData.json +++ b/src/pages/desktop/index/mock/userData.json @@ -56,6 +56,13 @@ "alt": "鍒嗗竷寮忚皟搴�", "type": "2", "url": "http://www.justlive.vip/center/" + }, + { + "id": "9", + "src": "../../images/gitee.png", + "alt": "绠楁硶绠$悊", + "type": "2", + "url": "/view/algorithmManage" } ] } diff --git a/src/pages/index/app.vue b/src/pages/index/app.vue index 26f9550..320b1ab 100644 --- a/src/pages/index/app.vue +++ b/src/pages/index/app.vue @@ -138,8 +138,9 @@ type: 'success', message: '鐧诲綍鎴愬姛锛�' }) - await this.getMenuList() - this.$router.push('/Layout/Video') + // await this.getMenuList() + // this.$router.push('/Layout/Video') + location.assign("/view/desktop") return json } else { this.$notify({ -- Gitblit v1.8.0