Commit 4b98e0d0 authored by daniel's avatar daniel

feat(iconPicker): 新增图标集选择弹框

parent f2b71c1e
...@@ -243,6 +243,116 @@ ...@@ -243,6 +243,116 @@
top: 0; top: 0;
left: 0; left: 0;
} }
/* 图标选择器弹框 */
.icon-picker-mask {
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background: rgba(0,0,0,0.5);
z-index: 200;
}
.icon-picker-dialog {
position: fixed;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 720px; height: 520px;
background: #fff;
border-radius: 8px;
z-index: 201;
display: flex;
flex-direction: column;
overflow: hidden;
}
.icon-picker-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 20px;
border-bottom: 1px solid #eee;
font-size: 18px;
font-weight: 500;
}
.icon-picker-close {
cursor: pointer;
font-size: 22px;
color: #999;
}
.icon-picker-close:hover { color: #333; }
.icon-picker-body {
display: flex;
flex: 1;
overflow: hidden;
}
.icon-picker-cats {
width: 160px;
border-right: 1px solid #eee;
overflow-y: auto;
flex-shrink: 0;
}
.icon-picker-cat {
padding: 12px 16px;
cursor: pointer;
font-size: 14px;
color: #333;
border-left: 3px solid transparent;
transition: all .2s;
}
.icon-picker-cat:hover { background: #f5f5f5; }
.icon-picker-cat.active {
background: #fff5f5;
border-left-color: #ce3939;
color: #ce3939;
font-weight: 500;
}
.icon-picker-icons {
flex: 1;
padding: 16px;
overflow-y: auto;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
gap: 12px;
}
.icon-picker-item {
width: 72px; height: 72px;
border: 2px solid #eee;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all .2s;
overflow: hidden;
}
.icon-picker-item:hover {
border-color: #ce3939;
box-shadow: 0 0 6px rgba(206,57,57,0.2);
}
.icon-picker-item img {
max-width: 60px;
max-height: 60px;
object-fit: contain;
}
.icon-picker-empty {
width: 100%;
text-align: center;
color: #999;
padding-top: 60px;
font-size: 14px;
}
.btn-pick-icon {
display: inline-block;
padding: 6px 16px;
background: #ce3939;
color: #fff;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-left: 10px;
vertical-align: middle;
}
.btn-pick-icon:hover { background: #b52e2e; }
</style> </style>
</head> </head>
...@@ -369,6 +479,7 @@ ...@@ -369,6 +479,7 @@
style="font-size: 12px;display: inline-block;border-radius: 50%;height: 18px;width: 18px;background: #ce3939;color: white;text-align: center;">注</span> style="font-size: 12px;display: inline-block;border-radius: 50%;height: 18px;width: 18px;background: #ce3939;color: white;text-align: center;">注</span>
<span style="display: inline">建议分辨率500*500</span> <span style="display: inline">建议分辨率500*500</span>
</span> </span>
<div style="display:flex;align-items:flex-end;gap:10px;">
<div> <div>
<label for="file"> <label for="file">
<div v-if="!module.icon" class="cover"> <div v-if="!module.icon" class="cover">
...@@ -378,6 +489,8 @@ ...@@ -378,6 +489,8 @@
</label> </label>
<input id="file" type="file" style="display: none" @change="uploadFile"> <input id="file" type="file" style="display: none" @change="uploadFile">
</div> </div>
<span class="btn-pick-icon" @click="openIconPicker">选择图标</span>
</div>
</div> </div>
<!-- 状态 (status) --> <!-- 状态 (status) -->
<div class="func"> <div class="func">
...@@ -401,6 +514,37 @@ ...@@ -401,6 +514,37 @@
style="position: fixed;height: 100%;width: 100%;background: black;z-index: 10;opacity: 0.5;top:0px;left:0px"> style="position: fixed;height: 100%;width: 100%;background: black;z-index: 10;opacity: 0.5;top:0px;left:0px">
</div> </div>
<!-- 图标选择器弹框 -->
<div class="icon-picker-mask" v-show="iconPickerVisible" @click.self="iconPickerVisible=false"></div>
<div class="icon-picker-dialog" v-show="iconPickerVisible">
<div class="icon-picker-header">
<span>选择图标</span>
<span class="icon-picker-close" @click="iconPickerVisible=false">&times;</span>
</div>
<div class="icon-picker-body">
<div class="icon-picker-cats">
<div class="icon-picker-cat"
v-for="cat in iconCategories"
:key="cat.id"
:class="{active: iconActiveCatId === cat.id}"
@click="selectCategory(cat.id)">
{{cat.name}}
</div>
</div>
<div class="icon-picker-icons">
<div v-if="iconList.length === 0" class="icon-picker-empty">暂无图标</div>
<div class="icon-picker-item"
v-for="icon in iconList"
:key="icon.id"
:style="{background: iconBgColor}"
@click="pickIcon(icon.url)">
<img :src="icon.url" :alt="icon.name" :title="icon.name" />
</div>
</div>
</div>
</div>
</div> </div>
<script src="${ctxStatic}/vue/vue.js"></script> <script src="${ctxStatic}/vue/vue.js"></script>
<script> <script>
...@@ -410,6 +554,11 @@ ...@@ -410,6 +554,11 @@
data: { data: {
list: [], list: [],
dialog: false, dialog: false,
iconPickerVisible: false,
iconCategories: [],
iconList: [],
iconActiveCatId: null,
iconBgColor: '${cmpt.cmptbgColor == null ? "#49b4b7" : cmpt.cmptbgColor}',
title: '新增服务模块', title: '新增服务模块',
module: { module: {
"id": null, "id": null,
...@@ -599,6 +748,47 @@ ...@@ -599,6 +748,47 @@
}) })
}; };
},
// 图标选择器
openIconPicker: function () {
this.iconPickerVisible = true;
if (this.iconCategories.length === 0) {
this.fetchIconCategories();
}
},
fetchIconCategories: function () {
$.ajax({
url: 'http://localhost:8081/assistant/v1/icon-category/list',
type: 'post',
contentType: 'application/json',
data: JSON.stringify({ status: 1 }),
success: (res) => {
var list = res.data || res.content || res || [];
this.iconCategories = Array.isArray(list) ? list : [];
if (this.iconCategories.length > 0) {
this.selectCategory(this.iconCategories[0].id);
}
}
});
},
selectCategory: function (catId) {
this.iconActiveCatId = catId;
$.ajax({
url: 'http://localhost:8081/assistant/v1/icon/list',
type: 'post',
contentType: 'application/json',
data: JSON.stringify({ categoryId: catId, status: 1 }),
success: (res) => {
var list = res.data || res.content || res || [];
this.iconList = Array.isArray(list) ? list : [];
}
});
},
pickIcon: function (url) {
this.module.icon = url;
this.iconPickerVisible = false;
this.$forceUpdate();
} }
} }
}); });
......
...@@ -205,6 +205,116 @@ ...@@ -205,6 +205,116 @@
justify-content: flex-end; justify-content: flex-end;
margin: 30px 20px; margin: 30px 20px;
} }
/* 图标选择器弹框 */
.icon-picker-mask {
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background: rgba(0,0,0,0.5);
z-index: 200;
}
.icon-picker-dialog {
position: fixed;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 720px; height: 520px;
background: #fff;
border-radius: 8px;
z-index: 201;
display: flex;
flex-direction: column;
overflow: hidden;
}
.icon-picker-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 20px;
border-bottom: 1px solid #eee;
font-size: 18px;
font-weight: 500;
}
.icon-picker-close {
cursor: pointer;
font-size: 22px;
color: #999;
}
.icon-picker-close:hover { color: #333; }
.icon-picker-body {
display: flex;
flex: 1;
overflow: hidden;
}
.icon-picker-cats {
width: 160px;
border-right: 1px solid #eee;
overflow-y: auto;
flex-shrink: 0;
}
.icon-picker-cat {
padding: 12px 16px;
cursor: pointer;
font-size: 14px;
color: #333;
border-left: 3px solid transparent;
transition: all .2s;
}
.icon-picker-cat:hover { background: #f5f5f5; }
.icon-picker-cat.active {
background: #fff5f5;
border-left-color: #ce3939;
color: #ce3939;
font-weight: 500;
}
.icon-picker-icons {
flex: 1;
padding: 16px;
overflow-y: auto;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
gap: 12px;
}
.icon-picker-item {
width: 72px; height: 72px;
border: 2px solid #eee;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all .2s;
overflow: hidden;
}
.icon-picker-item:hover {
border-color: #ce3939;
box-shadow: 0 0 6px rgba(206,57,57,0.2);
}
.icon-picker-item img {
max-width: 60px;
max-height: 60px;
object-fit: contain;
}
.icon-picker-empty {
width: 100%;
text-align: center;
color: #999;
padding-top: 60px;
font-size: 14px;
}
.btn-pick-icon {
display: inline-block;
padding: 6px 16px;
background: #ce3939;
color: #fff;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-left: 10px;
vertical-align: middle;
}
.btn-pick-icon:hover { background: #b52e2e; }
</style> </style>
</head> </head>
...@@ -310,6 +420,7 @@ ...@@ -310,6 +420,7 @@
style="font-size: 12px;display: inline-block;border-radius: 50%;height: 18px;width: 18px;background: #ce3939;color: white;text-align: center;">注</span> style="font-size: 12px;display: inline-block;border-radius: 50%;height: 18px;width: 18px;background: #ce3939;color: white;text-align: center;">注</span>
<span style="display: inline">建议分辨率80*80</span> <span style="display: inline">建议分辨率80*80</span>
</span> </span>
<div style="display:flex;align-items:flex-end;gap:10px;">
<div> <div>
<label for="icon"> <label for="icon">
<div v-if="!letter.icon" class="cover"> <div v-if="!letter.icon" class="cover">
...@@ -319,6 +430,8 @@ ...@@ -319,6 +430,8 @@
</label> </label>
<input id="icon" type="file" style="display: none" @change="uploadIconFile"> <input id="icon" type="file" style="display: none" @change="uploadIconFile">
</div> </div>
<span class="btn-pick-icon" @click="openIconPicker">选择图标</span>
</div>
</div> </div>
<div class="func"> <div class="func">
<span class="title-new">有效期</span> <span class="title-new">有效期</span>
...@@ -389,6 +502,36 @@ ...@@ -389,6 +502,36 @@
</div> </div>
<!-- 图标选择器弹框 -->
<div class="icon-picker-mask" v-show="iconPickerVisible" @click.self="iconPickerVisible=false"></div>
<div class="icon-picker-dialog" v-show="iconPickerVisible">
<div class="icon-picker-header">
<span>选择图标</span>
<span class="icon-picker-close" @click="iconPickerVisible=false">&times;</span>
</div>
<div class="icon-picker-body">
<div class="icon-picker-cats">
<div class="icon-picker-cat"
v-for="cat in iconCategories"
:key="cat.id"
:class="{active: iconActiveCatId === cat.id}"
@click="selectCategory(cat.id)">
{{cat.name}}
</div>
</div>
<div class="icon-picker-icons">
<div v-if="iconList.length === 0" class="icon-picker-empty">暂无图标</div>
<div class="icon-picker-item"
v-for="icon in iconList"
:key="icon.id"
:style="{background: iconBgColor}"
@click="pickIcon(icon.url)">
<img :src="icon.url" :alt="icon.name" :title="icon.name" />
</div>
</div>
</div>
</div>
</div> </div>
<script src="${ctxStatic}/vue/vue.js"></script> <script src="${ctxStatic}/vue/vue.js"></script>
<script> <script>
...@@ -412,6 +555,11 @@ ...@@ -412,6 +555,11 @@
}, },
list: [], list: [],
dialog: false, dialog: false,
iconPickerVisible: false,
iconCategories: [],
iconList: [],
iconActiveCatId: null,
iconBgColor: '${cmpt.cmptbgColor == null ? "#49b4b7" : cmpt.cmptbgColor}',
// 子类目 类型配置(1 网页 2 小程序(appId,path) 3 短链接(#小程序://) 4 页面(小程序) 5文档word,pdf 6 图片 png) // 子类目 类型配置(1 网页 2 小程序(appId,path) 3 短链接(#小程序://) 4 页面(小程序) 5文档word,pdf 6 图片 png)
typeDesc: { typeDesc: {
8: { 8: {
...@@ -737,6 +885,47 @@ ...@@ -737,6 +885,47 @@
}) })
}; };
},
// 图标选择器
openIconPicker: function () {
this.iconPickerVisible = true;
if (this.iconCategories.length === 0) {
this.fetchIconCategories();
}
},
fetchIconCategories: function () {
$.ajax({
url: 'http://localhost:8081/assistant/v1/icon-category/list',
type: 'post',
contentType: 'application/json',
data: JSON.stringify({ status: 1 }),
success: (res) => {
var list = res.data || res.content || res || [];
this.iconCategories = Array.isArray(list) ? list : [];
if (this.iconCategories.length > 0) {
this.selectCategory(this.iconCategories[0].id);
}
}
});
},
selectCategory: function (catId) {
this.iconActiveCatId = catId;
$.ajax({
url: 'http://localhost:8081/assistant/v1/icon/list',
type: 'post',
contentType: 'application/json',
data: JSON.stringify({ categoryId: catId, status: 1 }),
success: (res) => {
var list = res.data || res.content || res || [];
this.iconList = Array.isArray(list) ? list : [];
}
});
},
pickIcon: function (url) {
this.letter.icon = url;
this.iconPickerVisible = false;
this.$forceUpdate();
} }
} }
}); });
......
...@@ -246,6 +246,116 @@ ...@@ -246,6 +246,116 @@
top: 0; top: 0;
left: 0; left: 0;
} }
/* 图标选择器弹框 */
.icon-picker-mask {
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background: rgba(0,0,0,0.5);
z-index: 200;
}
.icon-picker-dialog {
position: fixed;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 720px; height: 520px;
background: #fff;
border-radius: 8px;
z-index: 201;
display: flex;
flex-direction: column;
overflow: hidden;
}
.icon-picker-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 20px;
border-bottom: 1px solid #eee;
font-size: 18px;
font-weight: 500;
}
.icon-picker-close {
cursor: pointer;
font-size: 22px;
color: #999;
}
.icon-picker-close:hover { color: #333; }
.icon-picker-body {
display: flex;
flex: 1;
overflow: hidden;
}
.icon-picker-cats {
width: 160px;
border-right: 1px solid #eee;
overflow-y: auto;
flex-shrink: 0;
}
.icon-picker-cat {
padding: 12px 16px;
cursor: pointer;
font-size: 14px;
color: #333;
border-left: 3px solid transparent;
transition: all .2s;
}
.icon-picker-cat:hover { background: #f5f5f5; }
.icon-picker-cat.active {
background: #fff5f5;
border-left-color: #ce3939;
color: #ce3939;
font-weight: 500;
}
.icon-picker-icons {
flex: 1;
padding: 16px;
overflow-y: auto;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
gap: 12px;
}
.icon-picker-item {
width: 72px; height: 72px;
border: 2px solid #eee;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all .2s;
overflow: hidden;
}
.icon-picker-item:hover {
border-color: #ce3939;
box-shadow: 0 0 6px rgba(206,57,57,0.2);
}
.icon-picker-item img {
max-width: 60px;
max-height: 60px;
object-fit: contain;
}
.icon-picker-empty {
width: 100%;
text-align: center;
color: #999;
padding-top: 60px;
font-size: 14px;
}
.btn-pick-icon {
display: inline-block;
padding: 6px 16px;
background: #ce3939;
color: #fff;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-left: 10px;
vertical-align: middle;
}
.btn-pick-icon:hover { background: #b52e2e; }
</style> </style>
</head> </head>
...@@ -457,6 +567,7 @@ ...@@ -457,6 +567,7 @@
style="font-size: 12px;display: inline-block;border-radius: 50%;height: 18px;width: 18px;background: #ce3939;color: white;text-align: center;">注</span> style="font-size: 12px;display: inline-block;border-radius: 50%;height: 18px;width: 18px;background: #ce3939;color: white;text-align: center;">注</span>
<span style="display: inline">建议分辨率80*80</span> <span style="display: inline">建议分辨率80*80</span>
</span> </span>
<div style="display:flex;align-items:flex-end;gap:10px;">
<div> <div>
<label for="iconUrl"> <label for="iconUrl">
<div v-if="!service.iconUrl" class="cover"> <div v-if="!service.iconUrl" class="cover">
...@@ -467,6 +578,8 @@ ...@@ -467,6 +578,8 @@
<input id="iconUrl" type="file" style="display: none" <input id="iconUrl" type="file" style="display: none"
@change="uploadIconFile"> @change="uploadIconFile">
</div> </div>
<span class="btn-pick-icon" @click="openIconPicker">选择图标</span>
</div>
</div> </div>
<div class="func"> <div class="func">
<span class="title-new">封面</span> <span class="title-new">封面</span>
...@@ -551,6 +664,37 @@ ...@@ -551,6 +664,37 @@
style="position: fixed;height: 100%;width: 100%;background: black;z-index: 10;opacity: 0.5;top:0px;left:0px"> style="position: fixed;height: 100%;width: 100%;background: black;z-index: 10;opacity: 0.5;top:0px;left:0px">
</div> </div>
<!-- 图标选择器弹框 -->
<div class="icon-picker-mask" v-show="iconPickerVisible" @click.self="iconPickerVisible=false"></div>
<div class="icon-picker-dialog" v-show="iconPickerVisible">
<div class="icon-picker-header">
<span>选择图标</span>
<span class="icon-picker-close" @click="iconPickerVisible=false">&times;</span>
</div>
<div class="icon-picker-body">
<div class="icon-picker-cats">
<div class="icon-picker-cat"
v-for="cat in iconCategories"
:key="cat.id"
:class="{active: iconActiveCatId === cat.id}"
@click="selectCategory(cat.id)">
{{cat.name}}
</div>
</div>
<div class="icon-picker-icons">
<div v-if="iconList.length === 0" class="icon-picker-empty">暂无图标</div>
<div class="icon-picker-item"
v-for="icon in iconList"
:key="icon.id"
:style="{background: iconBgColor}"
@click="pickIcon(icon.url)">
<img :src="icon.url" :alt="icon.name" :title="icon.name" />
</div>
</div>
</div>
</div>
</div> </div>
<script src="${ctxStatic}/vue/vue.js"></script> <script src="${ctxStatic}/vue/vue.js"></script>
<script> <script>
...@@ -561,6 +705,11 @@ ...@@ -561,6 +705,11 @@
editor: null, editor: null,
list: [], list: [],
dialog: false, dialog: false,
iconPickerVisible: false,
iconCategories: [],
iconList: [],
iconActiveCatId: null,
iconBgColor: '${cmpt.cmptbgColor == null ? "#49b4b7" : cmpt.cmptbgColor}',
title: '新增自助服务', title: '新增自助服务',
service: { service: {
"id": null, "id": null,
...@@ -1100,6 +1249,47 @@ ...@@ -1100,6 +1249,47 @@
}) })
}; };
},
// 图标选择器
openIconPicker: function () {
this.iconPickerVisible = true;
if (this.iconCategories.length === 0) {
this.fetchIconCategories();
}
},
fetchIconCategories: function () {
$.ajax({
url: 'http://localhost:8081/assistant/v1/icon-category/list',
type: 'post',
contentType: 'application/json',
data: JSON.stringify({ status: 1 }),
success: (res) => {
var list = res.data || res.content || res || [];
this.iconCategories = Array.isArray(list) ? list : [];
if (this.iconCategories.length > 0) {
this.selectCategory(this.iconCategories[0].id);
}
}
});
},
selectCategory: function (catId) {
this.iconActiveCatId = catId;
$.ajax({
url: 'http://localhost:8081/assistant/v1/icon/list',
type: 'post',
contentType: 'application/json',
data: JSON.stringify({ categoryId: catId, status: 1 }),
success: (res) => {
var list = res.data || res.content || res || [];
this.iconList = Array.isArray(list) ? list : [];
}
});
},
pickIcon: function (url) {
this.service.iconUrl = url;
this.iconPickerVisible = false;
this.$forceUpdate();
} }
} }
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment