Browse Source

大屏管理

master
xuhuajiao 1 month ago
parent
commit
cc6697275c
  1. 42
      src/assets/iconfonts/light/iconfont.css
  2. 2
      src/assets/iconfonts/light/iconfont.js
  3. 63
      src/assets/iconfonts/light/iconfont.json
  4. BIN
      src/assets/iconfonts/light/iconfont.ttf
  5. BIN
      src/assets/iconfonts/light/iconfont.woff
  6. BIN
      src/assets/iconfonts/light/iconfont.woff2
  7. BIN
      src/assets/images/screen/geo.png
  8. 297
      src/assets/styles/digitalScreen.scss
  9. 2
      src/assets/styles/sidebar.scss
  10. 571
      src/views/digitalScreen/index.vue
  11. 154
      src/views/digitalScreen/module/addBookDialog.vue
  12. 403
      src/views/digitalScreen/module/areaSetting.vue

42
src/assets/iconfonts/light/iconfont.css

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 3966148 */
src: url('iconfont.woff2?t=1736498949884') format('woff2'),
url('iconfont.woff?t=1736498949884') format('woff'),
url('iconfont.ttf?t=1736498949884') format('truetype');
src: url('iconfont.woff2?t=1755072475931') format('woff2'),
url('iconfont.woff?t=1755072475931') format('woff'),
url('iconfont.ttf?t=1755072475931') format('truetype');
}
.iconfont {
@ -13,6 +13,42 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-fuzhichenggong1:before {
content: "\e696";
}
.icon-fuzhi:before {
content: "\ec7a";
}
.icon-jiantou-sanjiao-shang:before {
content: "\e697";
}
.icon-tuoguanhetong:before {
content: "\e694";
}
.icon-weituo:before {
content: "\e695";
}
.icon-yijiantiquwenzi:before {
content: "\e692";
}
.icon-fasong-jiantou:before {
content: "\e9d6";
}
.icon-wenjianjiexi:before {
content: "\e82f";
}
.icon-shendusikao:before {
content: "\e876";
}
.icon-zhongduanjiankong:before {
content: "\e691";
}

2
src/assets/iconfonts/light/iconfont.js
File diff suppressed because it is too large
View File

63
src/assets/iconfonts/light/iconfont.json

@ -5,6 +5,69 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "40338657",
"name": "复制成功-copy",
"font_class": "fuzhichenggong1",
"unicode": "e696",
"unicode_decimal": 59030
},
{
"icon_id": "5993150",
"name": "复制",
"font_class": "fuzhi",
"unicode": "ec7a",
"unicode_decimal": 60538
},
{
"icon_id": "10943054",
"name": "箭头-三角-上",
"font_class": "jiantou-sanjiao-shang",
"unicode": "e697",
"unicode_decimal": 59031
},
{
"icon_id": "13091314",
"name": "托管合同",
"font_class": "tuoguanhetong",
"unicode": "e694",
"unicode_decimal": 59028
},
{
"icon_id": "16327703",
"name": "委托",
"font_class": "weituo",
"unicode": "e695",
"unicode_decimal": 59029
},
{
"icon_id": "42551369",
"name": "一键提取文字",
"font_class": "yijiantiquwenzi",
"unicode": "e692",
"unicode_decimal": 59026
},
{
"icon_id": "41794940",
"name": "发送-箭头",
"font_class": "fasong-jiantou",
"unicode": "e9d6",
"unicode_decimal": 59862
},
{
"icon_id": "40591561",
"name": "文件解析",
"font_class": "wenjianjiexi",
"unicode": "e82f",
"unicode_decimal": 59439
},
{
"icon_id": "43375318",
"name": "深度思考",
"font_class": "shendusikao",
"unicode": "e876",
"unicode_decimal": 59510
},
{
"icon_id": "18610501",
"name": "终端监控",

BIN
src/assets/iconfonts/light/iconfont.ttf

BIN
src/assets/iconfonts/light/iconfont.woff

BIN
src/assets/iconfonts/light/iconfont.woff2

BIN
src/assets/images/screen/geo.png

After

Width: 545  |  Height: 285  |  Size: 13 KiB

297
src/assets/styles/digitalScreen.scss

@ -0,0 +1,297 @@
.config-title{
display: flex;
justify-content: flex-start;
align-items: center;
color: #0c0e1e;
height: 32px;
line-height: 32px;
margin-bottom: 16px;
overflow: hidden;
p{
font-weight: bold;
width: 90px;
}
.title-readonly {
width: 600px;
height: 32px;
line-height: 32px;
padding: 0 15px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background-color: #fff;
cursor: default;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #606266;
font-size: 13px;
}
.double-click-btn{
margin: 0 0 0 20px;
color: #f56c6c;
}
}
.screen-content-title{
display: flex;
justify-content: flex-start;
align-items: center;
border-left: 3px solid #0348F3;
line-height: 30px;
padding-left: 10px;
font-size: 14px;
h4{
font-size: 18px;
color: #0c0e1e;
margin-right: 10px;
}
.el-tag{
margin-right: 10px;
}
.el-tag--small{
background-color: #e7faf0;
border-color: #d0f5e0;
color: #12C47A;
}
.el-tag--danger{
background-color: #ffeded;
border-color: #f65163;
color: #f65163;
}
p{
span{
display: inline-block;
padding: 0 3px;
font-weight: bold;
color: #0348F3;
}
}
}
.screen-remarks{
margin-top: 12px;
padding: 8px;
background-color: #EEF5FE;
font-size: 14px;
line-height: 22px;
border-radius: 4px;
}
.area-config{
.config-item{
padding: 15px 0;
}
.config-item-main{
display: flex;
justify-content: flex-start;
align-items: flex-start;
line-height: 32px;
.data-title{
display: block;
width: 80px;
text-align: right;
margin-right: 20px;
}
.el-radio-group{
.el-radio{
line-height: 32px;
}
}
}
.library-form{
padding-left: 70px;
margin-top: 10px;
.el-input{
width: 240px !important;
}
.config-remarks{
margin-left: 100px;
}
.edit-readonly {
width: 240px !important;
}
}
.el-form{
.el-input{
width: 340px;
margin-right: 20px;
}
.edit-readonly{
width: 340px;
}
::v-deep .el-form-item__content{
height: 40px;
overflow: hidden;
}
}
.edit-readonly {
display: inline-block;
height: 32px;
line-height: 32px;
padding: 0 15px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background-color: #fff;
margin-right: 20px;
cursor: default;
color: #606266;
font-size: 13px;
&:hover {
border-color: #c0c4cc;
}
}
.config-remarks{
font-size: 12px;
line-height: 18px;
color: #9098a4;
margin-left: 200px;
}
.upload-item{
display: flex;
justify-content: flex-start;
p{
width: 100px;
text-align: right;
font-size: 14px;
color: #606266;
padding: 0 12px 0 0;
font-weight: bold;
}
}
.avatar-uploader {
::v-deep .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
&:hover {
border-color: #409EFF;
}
}
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
}
.avatar {
width: 100px;
height: 100px;
display: block;
}
.book-list-upload{
display: flex;
flex-wrap: nowrap;
gap: 10px;
overflow-x: auto; // 超出宽度时显示横向滚动条
scrollbar-width: thin;
max-width: 1000px;
}
.book-swiper-wrapper {
position: relative;
// width: 100%;
max-width: 970px;
overflow: hidden;
}
.book-swiper {
width: 100%;
}
.book-list-item{
position: relative;
width: 110px;
height: 160px;
flex-shrink: 0; // 禁止压缩保持固定尺寸
overflow: hidden;
border: 1px solid #fff;
border-radius: 4px;
transition: all 0.2s;
&:hover {
border-color: #0348F3; // hover时高亮边框
box-shadow: 0 2px 8px rgba(3, 72, 243, 0.1);
}
img{
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.book-select, .book-delete {
position: absolute;
bottom: 3px;
display: flex;
align-items: center;
justify-content: center;
cursor: default;
transition: all 0.2s;
z-index: 10;
.iconfont{
font-size: 18px;
}
}
.book-select {
left: 3px;
.icon-wancheng {
display: none;
color: #0348F3;
}
.icon-weixuan {
color: #A6ADB6;
}
}
.book-delete {
right: 3px;
.icon-shanchu {
font-size: 16px;
color: #ED4A41;
}
}
// 选中状态样式
&:has(.icon-wancheng:not([style*="display: none"])) {
.icon-wancheng {
display: block;
}
.icon-weixuan {
display: none;
}
border-color: #0348F3;
}
}
.book-upload-btn{
width: 160px;
height: 160px;
text-align: center;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
margin: 0 0 0 10px;
.iconfont {
line-height: 160px;
font-size: 30px;
color: #8c939d;
}
}
.book-recommend{
position: relative;
padding-bottom: 40px;
}
.batch-delete-btn{
position: absolute;
bottom: 0;
left: 100px;
}
}
// 输入框聚焦样式增强
::v-deep .el-input__inner:focus {
border-color: #0348f3;
box-shadow: 0 0 0 2px rgba(3, 72, 243, 0.2);
}

2
src/assets/styles/sidebar.scss

@ -18,7 +18,7 @@
top: $headerHeight;
bottom: 0;
left: 0;
z-index: 99999;
z-index: 200;
@include bg_color;
@include siderBar-set;
padding-bottom: 50px;

571
src/views/digitalScreen/index.vue

@ -69,41 +69,243 @@
<p v-if="currentScreenItem.id === 5">{{ currentScreenItem.name }}为系统默认第5屏整屏显示宣传图片支持多图片切换</p>
</div>
<div class="area-config">
<div class="config-item">
<span class="data-title">到馆统计</span>
<el-radio-group v-model="arrival_library_setting" aria-hidden="false">
<el-radio :label="1">本地数据</el-radio>
<el-radio :label="2">基数计算</el-radio>
<el-radio :label="3">第三方接口</el-radio>
</el-radio-group>
<div v-if="currentScreenItem.id === 1" class="config-item">
<div class="config-item-main">
<span class="data-title">到馆统计</span>
<el-radio-group v-model="arrival_library_setting" aria-hidden="false">
<el-radio :label="1">本地数据</el-radio>
<el-radio :label="2">基数计算</el-radio>
<el-radio :label="3">第三方接口</el-radio>
</el-radio-group>
</div>
<div v-if="arrival_library_setting === 2" class="library-form">
<!-- 原到馆统计表单 -->
<el-form ref="librarySettingForm" :model="librarySettingForm" size="small" label-width="100px">
<el-form-item label="本年到馆" prop="visit_base">
<span v-if="!editStatus.librarySettingForm.visit_base" class="edit-readonly" @dblclick="handleDblClick('librarySettingForm', 'visit_base')">
{{ librarySettingForm.visit_base || '0' }}
</span>
<el-input v-else ref="librarySettingFormvisit_base" v-model="librarySettingForm.visit_base" type="number" @blur="handleBlur('librarySettingForm', 'visit_base')" @keyup.enter="handleBlur('librarySettingForm', 'visit_base')" />
<el-checkbox v-model="librarySettingForm.remarks" label="直接显示" name="form.remarks" />
</el-form-item>
<el-form-item label="去年到馆" prop="last_year_visit_base">
<span v-if="!editStatus.librarySettingForm.last_year_visit_base" class="edit-readonly" @dblclick="handleDblClick('librarySettingForm', 'last_year_visit_base')">
{{ librarySettingForm.last_year_visit_base || '0' }}
</span>
<el-input v-else ref="librarySettingFormlast_year_visit_base" v-model="librarySettingForm.last_year_visit_base" type="number" @blur="handleBlur('librarySettingForm', 'last_year_visit_base')" @keyup.enter="handleBlur('librarySettingForm', 'last_year_visit_base')" />
</el-form-item>
<el-form-item label="今日到馆" prop="today_visit">
<span v-if="!editStatus.librarySettingForm.today_visit" class="edit-readonly" @dblclick="handleDblClick('librarySettingForm', 'today_visit')">
{{ librarySettingForm.today_visit || '0' }} </span>
<el-input v-else ref="librarySettingFormtoday_visit" v-model="librarySettingForm.today_visit" type="number" @blur="handleBlur('librarySettingForm', 'today_visit')" @keyup.enter="handleBlur('librarySettingForm', 'today_visit')" />
<el-checkbox label="直接显示" name="form.remarks" />
</el-form-item>
<el-form-item label="昨日到馆" prop="yesterday_visit">
<span v-if="!editStatus.librarySettingForm.yesterday_visit" class="edit-readonly" @dblclick="handleDblClick('librarySettingForm', 'yesterday_visit')"> {{ librarySettingForm.yesterday_visit || '0' }} </span>
<el-input v-else ref="librarySettingFormyesterday_visit" v-model="librarySettingForm.yesterday_visit" type="number" @blur="handleBlur('librarySettingForm', 'yesterday_visit')" @keyup.enter="handleBlur('librarySettingForm', 'yesterday_visit')" />
<el-checkbox label="直接显示" name="form.remarks" />
</el-form-item>
<el-form-item label="本月到馆" prop="this_month_visit">
<span v-if="!editStatus.librarySettingForm.this_month_visit" class="edit-readonly" @dblclick="handleDblClick('librarySettingForm', 'this_month_visit')">
{{ librarySettingForm.this_month_visit || '0' }}
</span>
<el-input v-else ref="librarySettingFormthis_month_visit" v-model="librarySettingForm.this_month_visit" type="number" @blur="handleBlur('librarySettingForm', 'this_month_visit')" @keyup.enter="handleBlur('librarySettingForm', 'this_month_visit')" />
<el-checkbox label="直接显示" name="form.remarks" />
</el-form-item>
<el-form-item label="上月到馆" prop="last_month_visit">
<span v-if="!editStatus.librarySettingForm.last_month_visit" class="edit-readonly" @dblclick="handleDblClick('librarySettingForm', 'last_month_visit')">
{{ librarySettingForm.last_month_visit || '0' }}
</span>
<el-input v-else ref="librarySettingFormlast_month_visit" v-model="librarySettingForm.last_month_visit" type="number" @blur="handleBlur('librarySettingForm', 'last_month_visit')" @keyup.enter="handleBlur('librarySettingForm', 'last_month_visit')" />
<el-checkbox label="直接显示" name="form.remarks" />
</el-form-item>
</el-form>
<div class="config-remarks">双击输入框可进行编辑注意<br>
如未勾选直接显示系统根据本年到馆去年到馆所填数量自动生成今日到馆昨日到馆本月到馆上月到馆<br>
若勾选了直接显示系统会直接显示用户所填数量值注意未填写数量则显示为0
</div>
</div>
</div>
<div v-if="arrival_library_setting === 2">
<el-form ref="librarySettingForm" :model="librarySettingForm" label-width="80px">
<el-form-item label="本年到馆" prop="visit_base">
<el-input v-model="librarySettingForm.visit_base" />
<el-checkbox v-model="librarySettingForm.remarks" label="直接显示" name="form.remarks" />
</el-form-item>
<el-form-item label="去年到馆" prop="last_year_visit_base">
<el-input v-model="librarySettingForm.last_year_visit_base" />
</el-form-item>
<el-form-item label="今日到馆" prop="today_visit">
<el-input v-model="librarySettingForm.today_visit" />
<el-checkbox label="直接显示" name="form.remarks" />
</el-form-item>
<el-form-item label="昨日到馆" prop="yesterday_visit">
<el-input v-model="librarySettingForm.yesterday_visit" />
<el-checkbox label="直接显示" name="form.remarks" />
</el-form-item>
<el-form-item label="本月到馆" prop="this_month_visit">
<el-input v-model="librarySettingForm.this_month_visit" />
<el-checkbox label="直接显示" name="form.remarks" />
</el-form-item>
<el-form-item label="上月到馆" prop="last_month_visit">
<el-input v-model="librarySettingForm.last_month_visit" />
<el-checkbox label="直接显示" name="form.remarks" />
</el-form-item>
</el-form>
<div v-if="currentScreenItem.id !== 5" class="config-item">
<div class="config-item-main">
<span class="data-title">图创接口</span>
<!-- 原图创接口表单 -->
<el-form ref="openForm" :model="openForm" size="small" label-width="100px">
<el-form-item label="OpenLib地址" prop="open_lib_http">
<span
v-if="!editStatus.openForm.open_lib_http"
class="edit-readonly"
@dblclick="handleDblClick('openForm', 'open_lib_http')"
>
{{ openForm.open_lib_http || '' }}
</span>
<el-input
v-else
ref="openFormopen_lib_http"
v-model="openForm.open_lib_http"
@blur="handleBlur('openForm', 'open_lib_http')"
@keyup.enter="handleBlur('openForm', 'open_lib_http')"
/>
</el-form-item>
<el-form-item label="AppId" prop="open_lib_appId">
<span
v-if="!editStatus.openForm.open_lib_appId"
class="edit-readonly"
@dblclick="handleDblClick('openForm', 'open_lib_appId')"
>
{{ openForm.open_lib_appId || '' }}
</span>
<el-input
v-else
ref="openFormopen_lib_appId"
v-model="openForm.open_lib_appId"
@blur="handleBlur('openForm', 'open_lib_appId')"
@keyup.enter="handleBlur('openForm', 'open_lib_appId')"
/>
</el-form-item>
<el-form-item label="Secret" prop="open_lib_secret">
<span
v-if="!editStatus.openForm.open_lib_secret"
class="edit-readonly"
@dblclick="handleDblClick('openForm', 'open_lib_secret')"
>
{{ openForm.open_lib_secret || '' }}
</span>
<el-input
v-else
ref="openFormopen_lib_secret"
v-model="openForm.open_lib_secret"
@blur="handleBlur('openForm', 'open_lib_secret')"
@keyup.enter="handleBlur('openForm', 'open_lib_secret')"
/>
</el-form-item>
</el-form>
</div>
<div class="config-remarks">双击输入框可进行编辑数据将用于总览屏区域屏统计屏媒体屏在任意分屏编辑均可生效 </div>
</div>
<div v-if="currentScreenItem.id === 1" class="config-item">
<div class="config-item-main">
<span class="data-title">热门搜索</span>
<!-- 原热门搜索表单 -->
<el-form ref="hotForm" :model="hotForm" size="small" label-width="100px">
<el-form-item label="数据来源地址" prop="hot_search_http">
<span
v-if="!editStatus.hotForm.hot_search_http"
class="edit-readonly"
@dblclick="handleDblClick('hotForm', 'hot_search_http')"
>
{{ hotForm.hot_search_http || '' }}
</span>
<el-input
v-else
ref="hotFormhot_search_http"
v-model="hotForm.hot_search_http"
@blur="handleBlur('hotForm', 'hot_search_http')"
@keyup.enter="handleBlur('hotForm', 'hot_search_http')"
/>
</el-form-item>
</el-form>
</div>
<div class="config-remarks">双击输入框可进行编辑数据将用于总览屏 </div>
</div>
<div v-if="currentScreenItem.id === 1" class="config-item">
<div class="config-item-main">
<span class="data-title">微信绑定</span>
<!-- 原微信绑定表单 -->
<el-form ref="vxForm" :model="vxForm" size="small" label-width="100px">
<el-form-item label="AppID" prop="vx_appID">
<span
v-if="!editStatus.vxForm.vx_appID"
class="edit-readonly"
@dblclick="handleDblClick('vxForm', 'vx_appID')"
>
{{ vxForm.vx_appID || '' }}
</span>
<el-input
v-else
ref="vxFormvx_appID"
v-model="vxForm.vx_appID"
@blur="handleBlur('vxForm', 'vx_appID')"
@keyup.enter="handleBlur('vxForm', 'vx_appID')"
/>
</el-form-item>
<el-form-item label="AppSecret" prop="vx_AppSecret">
<span
v-if="!editStatus.vxForm.vx_AppSecret"
class="edit-readonly"
@dblclick="handleDblClick('vxForm', 'vx_AppSecret')"
>
{{ vxForm.vx_AppSecret || '' }}
</span>
<el-input
v-else
ref="vxFormvx_AppSecret"
v-model="vxForm.vx_AppSecret"
@blur="handleBlur('vxForm', 'vx_AppSecret')"
@keyup.enter="handleBlur('vxForm', 'vx_AppSecret')"
/>
</el-form-item>
</el-form>
</div>
<div class="config-remarks">双击输入框可进行编辑图书馆公众号AppIDAppSecrect 仅用于总览屏显示公众号粉丝数量</div>
</div>
<div v-if="currentScreenItem.id === 1 || currentScreenItem.id === 4" class="config-item">
<div class="config-item-main">
<span class="data-title">二维码</span>
<div class="upload-item">
<p>公众号二维码</p>
<el-upload
class="avatar-uploader"
action="https://jsonplaceholder.typicode.com/posts/"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="vxImageUrl" :src="vxImageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
</div>
</div>
<div class="config-remarks">双击可上传图片二维码用于总览屏媒体屏在任意分屏编辑均可生效</div>
</div>
<div v-if="currentScreenItem.id === 1" class="config-item">
<div class="config-item-main">
<span class="data-title">图书推荐</span>
<div class="upload-item book-recommend">
<p>推荐列表</p>
<div class="book-swiper-wrapper">
<swiper
ref="bookSwiper"
:options="swiperOptions"
class="book-swiper"
>
<swiper-slide
v-for="(book, index) in bookList"
:key="book.id"
class="book-list-item"
>
<img :src="book.url || require('@/assets/images/cover-bg.png')" alt="图书封面">
<span style="position: absolute; top: 0; left: 0;">{{ book.id }}</span>
<div class="book-select" @click.stop="toggleBookSelect(index)">
<i v-if="book.selected" class="iconfont icon-wancheng" />
<i v-else class="iconfont icon-weixuan" />
</div>
<div class="book-delete" @click.stop="deleteBook(index)">
<i class="iconfont icon-shanchu" />
</div>
</swiper-slide>
</swiper>
</div>
<div class="book-upload-btn" @click.stop="uploadBook"><i class="iconfont icon-shangchuan2" /></div>
<el-button class="batch-delete-btn" size="mini" :disabled="!hasSelectedItems" @click="batchDelete">
<i class="iconfont icon-shanchu" />
批量删除
</el-button>
</div>
</div>
</div>
<areaSetting v-if="currentScreenItem.id === 2" ref="areaSettingRef" />
</div>
</div>
</div>
@ -112,13 +314,26 @@
</div>
</div>
</transition>
<addBookDialog ref="addBookRef" />
</div>
</template>
<script>
import Sortable from 'sortablejs'
import { swiper, swiperSlide } from 'vue-awesome-swiper'
import 'swiper/dist/css/swiper.css'
import addBookDialog from './module/addBookDialog'
import areaSetting from './module/areaSetting'
export default {
name: 'DigitalScreen',
components: {
swiper,
swiperSlide,
addBookDialog,
areaSetting
},
data() {
return {
tabPosition: 'top',
@ -147,6 +362,67 @@ export default {
yesterday_visit: null,
this_month_visit: null,
last_month_visit: null
},
openForm: {
open_lib_http: null,
open_lib_appId: null,
open_lib_secret: null
},
hotForm: {
hot_search_http: null
},
vxForm: {
vx_appID: null,
vx_AppSecret: null
},
vxImageUrl: '',
editStatus: {
openForm: {
open_lib_http: false,
open_lib_appId: false,
open_lib_secret: false
},
hotForm: {
hot_search_http: false
},
vxForm: {
vx_appID: false,
vx_AppSecret: false
},
librarySettingForm: {
visit_base: false,
last_year_visit_base: false,
today_visit: false,
yesterday_visit: false,
this_month_visit: false,
last_month_visit: false
}
},
originalValues: {
openForm: {},
hotForm: {},
vxForm: {},
librarySettingForm: {}
},
bookList: [
{ id: 1, url: require('@/assets/images/cover-bg.png'), selected: false },
{ id: 2, url: require('@/assets/images/cover-bg.png'), selected: true },
{ id: 3, url: require('@/assets/images/cover-bg.png'), selected: false },
{ id: 4, url: require('@/assets/images/cover-bg.png'), selected: false },
{ id: 5, url: require('@/assets/images/cover-bg.png'), selected: false }
],
// Swiper
swiperOptions: {
slidesPerView: 'auto', //
spaceBetween: 10, //
freeMode: true, //
grabCursor: true, //
watchSlidesProgress: true,
on: {
resize: function() {
this.update() // resize
}
}
}
}
},
@ -164,6 +440,9 @@ export default {
},
currentScreenItem() {
return this.screenItems[this.activeTab]
},
hasSelectedItems() {
return this.bookList.some(book => book.selected)
}
},
created() {
@ -232,17 +511,12 @@ export default {
draggable: '.config-screen-item',
onEnd({ newIndex, oldIndex }) {
if (newIndex === oldIndex) return
// ID
const activeItemId = that.screenItems[that.activeTab].id
//
const movedItem = that.screenItems.splice(oldIndex, 1)[0]
that.screenItems.splice(newIndex, 0, movedItem)
//
const newActiveIndex = that.screenItems.findIndex(item => item.id === activeItemId)
// Tab
if (newActiveIndex !== -1) {
that.activeTab = newActiveIndex
@ -258,7 +532,6 @@ export default {
if (this.clickTimer) {
clearTimeout(this.clickTimer)
}
// 300ms
this.clickTimer = setTimeout(() => {
this.isDoubleClick = false
@ -311,43 +584,139 @@ export default {
updateScreenTime(item) {
console.log(`更新大屏${item.id}播放时长为${item.time}`)
this.$message.success(`大屏${item.id}播放时长已更新`)
},
//
handleDblClick(formName, field) {
//
this.originalValues[formName][field] = this[formName][field]
//
this.editStatus[formName][field] = true
//
this.$nextTick(() => {
const input = this.$refs[`${formName}${field}`]
if (input) input.focus()
})
},
// /
handleBlur(formName, field) {
//
this.editStatus[formName][field] = false
//
if (this[formName][field] !== this.originalValues[formName][field]) {
this.saveEdit(formName, field)
}
},
//
saveEdit(formName, field) {
const value = this[formName][field]
console.log(`保存${formName}.${field}`, value)
if (!value) {
this.$message.warning(`${this.getFieldLabel(formName, field)}不能为空`)
this[formName][field] = this.originalValues[formName][field]
return
}
this.$message.success(`${this.getFieldLabel(formName, field)}更新成功`)
},
//
getFieldLabel(formName, field) {
const labels = {
openForm: {
open_lib_http: 'OpenLib地址',
open_lib_appId: 'AppId',
open_lib_secret: 'Secret'
},
hotForm: {
hot_search_http: '数据来源地址'
},
vxForm: {
vx_appID: '微信AppID',
vx_AppSecret: '微信AppSecret'
},
librarySettingForm: {
visit_base: '本年到馆',
last_year_visit_base: '去年到馆',
today_visit: '今日到馆',
yesterday_visit: '昨日到馆',
this_month_visit: '本月到馆',
last_month_visit: '上月到馆'
}
}
return labels[formName][field] || field
},
//
handleAvatarSuccess(res, file) {
this.vxImageUrl = URL.createObjectURL(file.raw)
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg'
const isLt2M = file.size / 1024 / 1024 < 2
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!')
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!')
}
return isJPG && isLt2M
},
//
toggleBookSelect(index) {
this.bookList[index].selected = !this.bookList[index].selected
},
deleteBook(index) {
this.$confirm('确定要删除这本图书吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
this.bookList.splice(index, 1)
this.$nextTick(() => {
this.$refs.bookSwiper.swiper.update()
})
this.$message.success('删除成功!')
}).catch(() => {
//
})
},
uploadBook() {
this.$refs.addBookRef.addBookDialogVisible = true
// const newBookId = Date.now()
// this.bookList.unshift({
// id: newBookId,
// url: require('@/assets/images/cover-bg.png'),
// selected: false
// })
// this.$nextTick(() => {
// this.$refs.bookSwiper.swiper.update()
// this.$refs.bookSwiper.swiper.slideTo(0, 300)
// })
},
batchDelete() {
const selectedCount = this.bookList.filter(book => book.selected).length
if (selectedCount === 0) return
this.$confirm(`确定要删除选中的 ${selectedCount} 本图书吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.bookList = this.bookList.filter(book => !book.selected)
this.$nextTick(() => {
this.$refs.bookSwiper.swiper.update()
})
this.$message.success(`已成功删除 ${selectedCount} 本图书`)
})
}
}
}
</script>
<style scoped lang="scss">
.config-title{
display: flex;
justify-content: flex-start;
align-items: center;
color: #0c0e1e;
line-height: 32px;
margin-bottom: 16px;
p{
font-weight: bold;
width: 90px;
}
.title-readonly {
width: 600px;
height: 32px;
line-height: 32px;
padding: 0 15px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background-color: #fff;
cursor: default;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #606266;
font-size: 13px;
}
.double-click-btn{
margin: 0 0 0 20px;
color: #f56c6c;
}
}
@import "~@/assets/styles/digitalScreen.scss";
.config-screen{
display: flex;
@ -467,11 +836,6 @@ export default {
}
}
// activeTabCSS
::v-deep .config-screen {
--active-index: v-bind(activeTab);
}
// +
.content-area {
height: 520px;
@ -496,58 +860,9 @@ export default {
opacity: 0;
}
.screen-content-title{
display: flex;
justify-content: flex-start;
align-items: center;
border-left: 3px solid #0348F3;
line-height: 30px;
padding-left: 10px;
font-size: 14px;
h4{
font-size: 18px;
color: #0c0e1e;
margin-right: 10px;
}
.el-tag{
margin-right: 10px;
}
.el-tag--small{
background-color: #e7faf0;
border-color: #d0f5e0;
color: #12C47A;
}
.el-tag--danger{
background-color: #ffeded;
border-color: #f65163;
color: #f65163;
}
p{
span{
display: inline-block;
padding: 0 3px;
font-weight: bold;
color: #0348F3;
}
}
}
.screen-remarks{
margin-top: 12px;
padding: 8px;
background-color: #EEF5FE;
font-size: 14px;
line-height: 22px;
border-radius: 4px;
}
.area-config{
.config-item{
display: flex;
justify-content: flex-start;
.data-title{
display: block;
width: 90px;
text-align: right;
}
}
// activeTabCSS
::v-deep .config-screen {
--active-index: v-bind(activeTab);
}
</style>

154
src/views/digitalScreen/module/addBookDialog.vue

@ -0,0 +1,154 @@
<template>
<el-dialog class="auto-dialog" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :before-close="handleClose" :visible.sync="addBookDialogVisible" title="新增图书推荐">
<div class="setting-dialog">
<el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="90px">
<div style="width: 696px;">
<el-form-item label="题名" prop="title">
<el-input v-model="form.title" placeholder="请输入" />
</el-form-item>
<el-form-item label="著者" prop="author">
<el-input v-model="form.author" placeholder="请输入" />
</el-form-item>
<el-form-item label="ISBN" prop="isbn">
<el-input v-model="form.isbn" placeholder="请输入" />
</el-form-item>
<el-form-item label="分类号" prop="classNo">
<el-input v-model="form.classNo" placeholder="请输入" />
</el-form-item>
<el-form-item label="出版年份" prop="publishYear">
<el-input v-model="form.publishYear" placeholder="请输入" />
</el-form-item>
<div>
<el-form-item label="出版社" prop="publisher">
<el-input v-model="form.publisher" placeholder="请输入" style="width: 586px;" />
</el-form-item>
</div>
<div>
<el-form-item label="简介" prop="remarks">
<el-input v-model="form.remarks" type="textarea" row="4" placeholder="请输入" style="width: 586px;" />
</el-form-item>
</div>
<UploadCover :label-name="labelName" :form="form" upload-type="book" @childCover="handleCover" />
</div>
<div v-if="form.bookCover" class="preview-cover">
<p>封面预览</p>
<img :src="bookCover" alt="">
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="handleClose">取消</el-button>
<el-button :loading="btnLoading" type="primary" @click="handleComfired">确认</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import UploadCover from '@/views/components/upload.vue'
import { mapGetters } from 'vuex'
export default {
name: 'Book',
components: { UploadCover },
data() {
return {
btnLoading: false,
addBookDialogVisible: false,
form: { id: null, title: null, author: null, isbn: null, classNo: null, publishYear: null, publisher: null, bookCover: null, bookRecNo: null, remarks: null },
bookCover: null,
labelName: '图书封面',
rules: {
title: [
{ required: true, message: '题名不可为空', trigger: 'blur' }
],
// author: [
// { required: true, message: '', trigger: 'blur' }
// ],
isbn: [
{ required: true, message: 'ISBN不可为空', trigger: 'blur' }
]
// classNo: [
// { required: true, message: '', trigger: 'blur' }
// ],
// publisher: [
// { required: true, message: '', trigger: 'blur' }
// ]
}
}
},
computed: {
...mapGetters([
'baseApi'
])
},
created() {
},
methods: {
handleCover(value) {
console.log(value)
if (value) {
this.form.bookCover = value
this.bookCover = this.baseApi + '/api/fileRelevant/getImg?imgType=2&imgId=' + value + '.jpg'
} else {
this.form.bookCover = null
this.bookCover = null
}
},
handleClose() {
this.addBookDialogVisible = false
},
handleComfired() {
this.$refs.form.validate((valid) => {
if (valid) {
this.addBookDialogVisible = false
// const ids = []
// this.selectBookData.forEach(val => {
// ids.push(val.id)
// })
// const params = {
// 'gridId': this.selectGridVal.id,
// 'ids': ids
// }
// console.log('params', params)
// FetchManualShelving(params).then(() => {
// this.$message({ message: '', type: 'success', offset: 8 })
// this.handleCloseDialog()
// }).catch(err => {
// console.log(err)
// this.addBookDialogVisible = false
// })
} else {
console.log('error submit!!')
return false
}
})
}
}
}
</script>
<style lang="scss" scoped>
.auto-dialog{
::v-deep .el-dialog{
width: initial;
}
}
.el-form{
display: flex;
justify-content: flex-start;
}
.preview-cover{
flex: 1;
padding-left: 10px;
p{
font-weight: bold;
color: #0c0e1e;
margin: -14px 0 10px 0;
}
img{
display: block;
height: 180px;
}
}
</style>

403
src/views/digitalScreen/module/areaSetting.vue

@ -0,0 +1,403 @@
<template>
<div>
<div class="config-item">
<div class="config-item-main">
<span class="data-title">地图DataV</span>
<el-form ref="areaForm" class="areaForm" :model="areaForm" size="small" label-width="100px">
<el-form-item label="GeoJSON" prop="geoJSON">
<span
v-if="!editStatus.areaForm.geoJSON"
class="edit-readonly"
@dblclick="handleDblClick('areaForm', 'geoJSON')"
>
{{ areaForm.geoJSON || '' }}
</span>
<el-input
v-else
ref="areaFormgeoJSON"
v-model="areaForm.geoJSON"
type="textarea"
rows="5"
@blur="handleBlur('areaForm', 'geoJSON')"
@keyup.enter="handleBlur('areaForm', 'geoJSON')"
/>
</el-form-item>
</el-form>
</div>
<div class="config-remarks">双击输入框可进行编辑数据将用于区域屏显示区域地图<i class="iconfont icon-zhuyi-lan" @click="geoJsonVisible=true" /></div>
</div>
<div class="config-item">
<div class="config-item-main">
<span class="data-title">总分馆管理</span>
<div class="upload-item" style="align-items: flex-start;">
<p>总分馆列表</p>
<el-card class="box-card" style="padding: 20px;">
<el-table
:data="tableData"
style="width: 100%"
max-height="360"
>
<el-table-column type="selection" align="center" width="55" />
<el-table-column prop="name" label="名称" width="150" />
<el-table-column prop="libCode" label="馆代码" width="100" />
<el-table-column prop="province" label="坐标" width="200" />
<el-table-column prop="number" label="宣传图片" width="80" />
<el-table-column fixed="right" label="操作" width="100">
<template>
<!-- slot-scope="scope" -->
<el-button style="padding: 5px 6px !important;"><i class="iconfont icon-bianji" />编辑</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
style="margin: 34px 0 10px 0 !important;"
:current-page="page.page"
:total="page.total"
:page-size="page.size"
:pager-count="5"
layout="total, prev, pager, next, sizes"
@size-change="handleSizeChange"
@current-change="handleCurrentPage"
/>
</el-card>
<!-- @click="toDelete(crud.selections)" -->
<div style="display: flex; flex-direction: column; justify-content: flex-start; margin-left: 15px;">
<el-button size="mini" @click="libDialogVisible=true">
<i class="iconfont icon-xinzeng" />
新增
</el-button>
<el-button size="mini" style="margin-left: 0; margin-top: 14px;">
<i class="iconfont icon-shanchu" />
删除
</el-button>
</div>
</div>
</div>
</div>
<el-dialog class="geoJson-dialog" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :before-close="handleClose" :visible.sync="geoJsonVisible" title="地图GeoJSON获取方法">
<div class="setting-dialog geo-remarks">
<p>1.开发网址
<a
:href="link"
target="_blank"
rel="noopener noreferrer"
class="external-link"
>
{{ link }}
</a>
<i class="iconfont" :class="copied ? 'icon-fuzhichenggong1' : 'icon-fuzhi'" @click="copyLink" />
</p>
<p style="padding: 15px 0;">2.在地图上找到并选择正确的区域区域最小单位是/</p>
<div style="display: flex; justify-content: space-between;">
<p>3.在右侧工具栏中找到<br>
其他类型GeoJSONSVG<br>
点击下方的GeoJSON后面的按钮<br>
复制代码粘贴到此处即可</p>
<img src="@/assets/images/screen/geo.png" alt="">
</div>
</div>
</el-dialog>
<el-dialog class="auto-dialog" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :before-close="handleClose" :visible.sync="libDialogVisible" title="新增分管">
<div class="setting-dialog">
<el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="90px">
<div style="width: 696px;">
<div>
<el-form-item label="名称" prop="title">
<el-input v-model="form.title" placeholder="请输入" style="width: 586px;" />
</el-form-item>
</div>
<el-form-item label="类型" prop="type">
<el-radio-group v-model="form.type" aria-hidden="false">
<el-radio :label="1">总馆</el-radio>
<el-radio :label="2">分馆</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="馆代码" prop="libCode" style="margin-left: 30px; margin-right: 0 !important;">
<el-input v-model="form.libCode" placeholder="请输入" />
</el-form-item>
<div>
<el-form-item label="面积" prop="areaNum">
<el-input v-model="form.areaNum" placeholder="请输入" style="width: 586px;">
<template slot="append">平方米</template>
</el-input>
</el-form-item>
</div>
<div>
<el-form-item label="地址" prop="place">
<el-input v-model="form.place" placeholder="请输入" style="width: 586px;" />
</el-form-item>
</div>
<div class="location-item">
<el-form-item label="坐标" prop="location">
<el-input v-model="form.location.x" placeholder="请输入">
<template slot="prepend">X</template>
</el-input>
<el-input v-model="form.location.y" placeholder="请输入">
<template slot="prepend">Y</template>
</el-input>
</el-form-item>
</div>
<div>
<el-form-item label="简介" prop="remarks">
<el-input v-model="form.remarks" type="textarea" rows="4" placeholder="请输入" style="width: 586px;" />
</el-form-item>
</div>
<div>
<el-form-item label="宣传图片" prop="remarks" />
<!--<div class="upload-container">
<i v-if="fileList.length === 0" class="iconfont icon-tianjiawenjian upload-icon" />
<div v-for="item in fileList" :key="item.name" class="file-list">
<i class="iconfont icon-xiaowenjian" />
{{ item.name }}
<i class="el-icon-close" @click="deleteFile(item)" />
</div>
<div class="upload-input">
<input ref="fileInput" type="file" multiple @change="changeAiFile">
<div class="upload-zip"><i class="iconfont icon-shangchuan2" />点击上传</div>
</div>
</div> -->
</div>
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="handleClose">取消</el-button>
<el-button :loading="btnLoading" type="primary" @click="handleComfired">确认</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'AreaSetting',
components: { },
data() {
return {
areaForm: {
geoJSON: null
},
editStatus: {
areaForm: {
geoJSON: false
}
},
originalValues: {
areaForm: {}
},
geoJsonVisible: false,
link: 'https://datav.aliyun.com/portal/school/atlas/area_selector',
copied: false,
tableData: [{
name: '总管',
libCode: 'lib001',
province: '114.133561,30.641408',
number: '3'
}, {
name: '分管1',
libCode: 'lib001',
province: '114.133561,30.641408',
number: '3'
}],
page: {
page: 1,
size: 10,
total: 0
},
libDialogVisible: false,
form: {
title: '',
type: 1,
libCode: '',
areaNum: '',
place: '',
location: { x: '', y: '' },
remarks: ''
},
rules: {
title: [
{ required: true, message: '名称不可为空', trigger: 'blur' }
],
type: [
{ required: true, message: '请选择类型', trigger: 'change' }
],
libCode: [
{ required: true, message: '馆代码不可为空', trigger: 'blur' }
]
}
}
},
computed: {
...mapGetters([
'baseApi'
])
},
created() {
},
methods: {
//
handleDblClick(formName, field) {
//
this.originalValues[formName][field] = this[formName][field]
//
this.editStatus[formName][field] = true
//
this.$nextTick(() => {
const input = this.$refs[`${formName}${field}`]
if (input) input.focus()
})
},
// /
handleBlur(formName, field) {
//
this.editStatus[formName][field] = false
//
if (this[formName][field] !== this.originalValues[formName][field]) {
this.saveEdit(formName, field)
}
},
//
saveEdit(formName, field) {
const value = this[formName][field]
console.log(`保存${formName}.${field}`, value)
if (!value) {
this.$message.warning(`${this.getFieldLabel(formName, field)}不能为空`)
this[formName][field] = this.originalValues[formName][field]
return
}
this.$message.success(`${this.getFieldLabel(formName, field)}更新成功`)
},
handleClose() {
this.geoJsonVisible = false
this.libDialogVisible = false
},
copyLink() {
//
navigator.clipboard.writeText(this.link)
.then(() => {
this.copied = true
// 2
setTimeout(() => {
this.copied = false
}, 2000)
})
.catch(err => {
console.error('无法复制内容: ', err)
// clipboard API
this.fallbackCopyText()
})
},
// Clipboard API
fallbackCopyText() {
const textArea = document.createElement('textarea')
textArea.value = this.link
textArea.style.position = 'fixed'
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
try {
const successful = document.execCommand('copy')
this.copied = successful
if (successful) {
setTimeout(() => {
this.copied = false
}, 2000)
}
} catch (err) {
console.error('复制失败: ', err)
}
document.body.removeChild(textArea)
},
handleSizeChange(size) {
this.page.size = size
this.page.page = 1
},
handleCurrentPage(val) {
this.page.page = val
},
handleComfired() {
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/assets/styles/digitalScreen.scss";
.edit-readonly{
width: 800px !important;
height: 110px !important;
line-height: 20px !important;
overflow: hidden;
overflow-y: scroll;
}
.areaForm{
::v-deep .el-form-item__content {
width: 800px !important;
height: 110px !important;
}
}
.icon-zhuyi-lan{
font-size: 20px;
color: #0348f3;
}
.geoJson-dialog{
::v-deep .el-dialog{
width: 850px;
.el-dialog__body{
padding: 10px 0 20px 0;
}
}
}
.geo-remarks{
font-size: 14px;
line-height: 30px;
.external-link {
color: #0348f3; /* Vue的默认主题色 */
text-decoration: none;
}
.external-link:hover {
text-decoration: underline;
}
.iconfont{
cursor: pointer;
margin-left: 6px;
font-size: 18px;
}
.icon-fuzhichenggong1{
font-size: 20px;
}
}
::v-deep .el-table tr .el-table__cell{
padding: 8px 0 !important;
}
.location-item{
::v-deep .el-form-item{
display: flex;
justify-content: flex-start;
margin-right: 0 !important;
.el-form-item__label{
}
.el-form-item__content{
width: 586px !important;
display: flex;
justify-content: space-between;
.el-input:first-child{
margin-right: 20px;
}
}
}
}
</style>
Loading…
Cancel
Save