mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-29 05:50:50 +00:00
Merge branch 'v8.0' of https://gitee.com/ZhongBangKeJi/CRMEB into v8.0
This commit is contained in:
commit
8ce140bdb2
@ -206,6 +206,8 @@ class RoutineTemplateController extends AuthController
|
||||
}
|
||||
$data['appId'] = sys_config('routine_appId');
|
||||
$data['help'] = 'https://doc.crmeb.com/web/single/crmeb_v4/978';
|
||||
// 站点网址:前端 iframe H5 预览地址回退使用(H5 产物部署在 backend/public)
|
||||
$data['site_url'] = sys_config('site_url');
|
||||
return app('json')->success($data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,8 +40,8 @@
|
||||
accept="image/png, image/jpeg, image/gif, image/jpg"
|
||||
@change="selectImg($event)"
|
||||
/>
|
||||
<el-button type="danger" plain icon="el-icon-zoom-in" v-db-click @click="changeScale(1)">放大</el-button>
|
||||
<el-button type="danger" plain icon="el-icon-zoom-out" v-db-click @click="changeScale(-1)">缩小</el-button>
|
||||
<el-button type="danger" plain icon="ZoomIn" v-db-click @click="changeScale(1)">放大</el-button>
|
||||
<el-button type="danger" plain icon="ZoomOut" v-db-click @click="changeScale(-1)">缩小</el-button>
|
||||
<el-button type="danger" plain v-db-click @click="rotateLeft">↺ 左旋转</el-button>
|
||||
<el-button type="danger" plain v-db-click @click="rotateRight">↻ 右旋转</el-button>
|
||||
</div>
|
||||
|
||||
@ -46,14 +46,14 @@
|
||||
>
|
||||
<el-button
|
||||
type="success"
|
||||
icon="el-icon-edit"
|
||||
icon="Edit"
|
||||
v-show="item.new[i].isDel && isShow"
|
||||
v-db-click
|
||||
@click="clkk(item)"
|
||||
></el-button>
|
||||
<el-button
|
||||
type="error"
|
||||
icon="el-icon-delete"
|
||||
icon="Delete"
|
||||
v-show="item.new[i].isDel && isShow"
|
||||
v-db-click
|
||||
@click="del(item, '删除图文', i)"
|
||||
@ -61,7 +61,7 @@
|
||||
></el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-s-promotion"
|
||||
icon="Promotion"
|
||||
v-show="item.new[i].isDel && isShowSend"
|
||||
v-db-click
|
||||
@click="send(item, '发送', i)"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<el-dialog v-model="visible" width="800px" title="选择图标" append-to-body>
|
||||
<div class="icon-selector">
|
||||
<div class="search-box">
|
||||
<el-input v-model="searchText" placeholder="搜索图标名称" prefix-icon="el-icon-search" clearable></el-input>
|
||||
<el-input v-model="searchText" placeholder="搜索图标名称" prefix-icon="Search" clearable></el-input>
|
||||
</div>
|
||||
<div class="icon-list">
|
||||
<div class="icon-item" v-for="(item, index) in filteredIcons" :key="index" @click="selectIcon(item)">
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
v-model="dialogVisible"
|
||||
width="1188px"
|
||||
top="5vh"
|
||||
custom-class="theme-dialog"
|
||||
class="theme-dialog"
|
||||
:show-close="false"
|
||||
append-to-body
|
||||
:modal="true"
|
||||
@ -43,21 +43,26 @@
|
||||
<el-input
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入主题名称"
|
||||
suffix-icon="el-icon-search"
|
||||
suffix-icon="Search"
|
||||
clearable
|
||||
@clear="searchTheme"
|
||||
@change="searchTheme"
|
||||
></el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-grid">
|
||||
<div class="theme-grid" v-loading="loading">
|
||||
<!-- 新建空白主题 -->
|
||||
<div class="theme-item create-new" v-if="activeTab === 'my'" @click="createNewTheme">
|
||||
<div class="theme-item create-new" v-if="activeTab === 'my'" v-db-click @click="createNewTheme">
|
||||
<div class="create-icon">
|
||||
<div class="iconfont iconic_brush"></div>
|
||||
</div>
|
||||
<div class="create-text">新建空白主题</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div class="theme-empty" v-if="!loading && themes.length === 0">未找到相关主题,换个关键词试试</div>
|
||||
|
||||
<!-- 主题列表 -->
|
||||
<div class="theme-item" v-for="(theme, index) in themes" :key="index">
|
||||
<div class="theme-cover">
|
||||
@ -85,8 +90,8 @@
|
||||
<div class="theme-time">修改时间:{{ theme.up_time }}</div>
|
||||
|
||||
<div class="theme-hover-actions">
|
||||
<div class="button default" @click="viewThemeDetail(theme)">查看详情</div>
|
||||
<div class="button primary" @click="selectTheme(theme)">使用主题</div>
|
||||
<div class="button default" v-db-click @click="viewThemeDetail(theme)">查看详情</div>
|
||||
<div class="button primary" v-db-click @click="selectTheme(theme)">使用主题</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -134,7 +139,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-btn">
|
||||
<el-button type="primary" @click="selectTheme(currentTheme)">使用主题</el-button>
|
||||
<el-button type="primary" v-db-click @click="selectTheme(currentTheme)">使用主题</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -143,6 +148,7 @@
|
||||
<div class="section-title">主题图片</div>
|
||||
<div class="images-list">
|
||||
<div class="image-item" v-for="(opt, index) in filterOptions" :key="index">
|
||||
<div class="image-label">{{ opt.label }}</div>
|
||||
<div class="phone-mockup">
|
||||
<img
|
||||
v-if="currentTheme[opt.value]"
|
||||
@ -228,6 +234,7 @@ const filterOptions = [
|
||||
{ label: '个人中心', value: 'user_image' },
|
||||
];
|
||||
const themes = ref([]);
|
||||
const loading = ref(false);
|
||||
const page = ref(1);
|
||||
const limit = ref(9);
|
||||
const total = ref(0);
|
||||
@ -261,10 +268,15 @@ function getList() {
|
||||
if (props.type == 'mall' && props.currentType == 'home') {
|
||||
reqData.page_type = 'all';
|
||||
}
|
||||
getThemeList(reqData).then((res) => {
|
||||
themes.value = res.data.list;
|
||||
total.value = res.data.count;
|
||||
});
|
||||
loading.value = true;
|
||||
getThemeList(reqData)
|
||||
.then((res) => {
|
||||
themes.value = res.data.list;
|
||||
total.value = res.data.count;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function handlePageChange(val) {
|
||||
@ -352,23 +364,8 @@ function searchTheme() {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 弹窗样式
|
||||
:deep(.theme-dialog) {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
.el-dialog__header {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding: 0px !important;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.el-dialog__body::-webkit-scrollbar {
|
||||
width: 0%;
|
||||
}
|
||||
}
|
||||
// 弹窗壳层(header/body/圆角)覆盖在本文件末尾的非 scoped 块中:
|
||||
// append-to-body 弹窗 teleport 到 body 后脱离组件样式作用域,scoped :deep 无法命中
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
@ -377,7 +374,7 @@ function searchTheme() {
|
||||
width: 100%;
|
||||
padding: 15px 24px;
|
||||
.dialog-header-tabs {
|
||||
background: #fff;
|
||||
background: var(--prev-bg-white);
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
@ -387,7 +384,7 @@ function searchTheme() {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
color: var(--prev-color-text-regular);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
@ -395,21 +392,30 @@ function searchTheme() {
|
||||
height: 12px;
|
||||
margin-left: 20px;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-icon-close {
|
||||
font-size: 16px;
|
||||
color: #909399;
|
||||
color: var(--prev-color-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: var(--prev-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100% - 100px);
|
||||
padding: 1px 24px 1px 24px !important;
|
||||
padding: 0 24px 24px !important;
|
||||
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
@ -417,12 +423,11 @@ function searchTheme() {
|
||||
overflow: hidden;
|
||||
.main-content {
|
||||
flex: 1;
|
||||
min-height: 756px;
|
||||
padding: 20px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
background: var(--prev-bg-white);
|
||||
.filters-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -441,42 +446,57 @@ function searchTheme() {
|
||||
gap: 30px;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
max-height: calc(100vh - 300px);
|
||||
|
||||
.theme-empty {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 60px 0;
|
||||
font-size: 13px;
|
||||
color: var(--prev-color-text-secondary);
|
||||
}
|
||||
|
||||
.theme-item {
|
||||
width: 204px;
|
||||
height: 295px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
background: var(--prev-bg-white);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #f0f0f0;
|
||||
border: 1px solid var(--prev-border-color-lighter);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: box-shadow 0.3s, border-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--prev-color-primary-light-5);
|
||||
box-shadow: 0 6px 16px rgba(0, 21, 41, 0.08);
|
||||
}
|
||||
|
||||
&.create-new {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
border: 1px solid #eee;
|
||||
background: #fafafa;
|
||||
border: 1px dashed var(--prev-border-color-base);
|
||||
background: var(--prev-bg-color);
|
||||
height: 295px; // Fixed height to match theme items
|
||||
transition: all 0.3s;
|
||||
|
||||
.iconic_brush {
|
||||
font-size: 40px;
|
||||
color: #ccc;
|
||||
color: var(--prev-color-text-placeholder);
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.create-text {
|
||||
color: #333;
|
||||
color: var(--prev-color-text-regular);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: var(--prev-color-primary);
|
||||
background: var(--prev-color-primary-light-9);
|
||||
.iconic_brush,
|
||||
.create-text {
|
||||
color: var(--prev-color-primary);
|
||||
@ -488,7 +508,7 @@ function searchTheme() {
|
||||
position: relative;
|
||||
height: 215px;
|
||||
overflow: hidden;
|
||||
background: #f0f2f5;
|
||||
background: var(--prev-bg-main-color);
|
||||
transition: height 0.3s;
|
||||
|
||||
.blur-bg {
|
||||
@ -508,10 +528,10 @@ function searchTheme() {
|
||||
z-index: 2;
|
||||
height: 95%;
|
||||
margin: 25px 24px 0 24px;
|
||||
background: #fff;
|
||||
background: var(--prev-bg-white);
|
||||
border-radius: 10px 10px 0 0;
|
||||
overflow: hidden;
|
||||
border: 2px solid #fff;
|
||||
border: 2px solid var(--prev-bg-white);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
@ -523,13 +543,13 @@ function searchTheme() {
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
color: var(--prev-color-text-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.theme-info {
|
||||
background: #fff;
|
||||
background: var(--prev-bg-white);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -539,7 +559,7 @@ function searchTheme() {
|
||||
.theme-title {
|
||||
padding: 12px 0px 0 12px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
color: var(--prev-color-text-regular);
|
||||
margin-bottom: 12px;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
@ -550,9 +570,9 @@ function searchTheme() {
|
||||
justify-content: space-between;
|
||||
.tag {
|
||||
font-weight: 400;
|
||||
color: rgba(2, 86, 255, 1);
|
||||
color: var(--prev-color-primary);
|
||||
font-size: 12px;
|
||||
background: rgba(2, 86, 255, 0.06);
|
||||
background: var(--prev-color-primary-light-9);
|
||||
padding: 4px 6px 4px 8px;
|
||||
border-radius: 10px 0 0 10px;
|
||||
}
|
||||
@ -562,7 +582,7 @@ function searchTheme() {
|
||||
padding: 0 12px 0 12px;
|
||||
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
color: var(--prev-color-text-secondary);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@ -586,7 +606,6 @@ function searchTheme() {
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
}
|
||||
.primary {
|
||||
background: var(--prev-color-primary);
|
||||
@ -596,10 +615,10 @@ function searchTheme() {
|
||||
}
|
||||
}
|
||||
.default {
|
||||
background: #f5f5f5;
|
||||
color: #606266;
|
||||
background: var(--prev-bg-color);
|
||||
color: var(--prev-color-text-primary);
|
||||
&:hover {
|
||||
background: #e4e7ed;
|
||||
background: var(--prev-border-color-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -624,33 +643,31 @@ function searchTheme() {
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-dialog__body) {
|
||||
max-height: calc(100vh - 100px) !important;
|
||||
}
|
||||
.detail-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - 100px);
|
||||
background: #f5f7fa;
|
||||
background: var(--prev-bg-color);
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 15px 20px 16px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #eee;
|
||||
background: var(--prev-bg-white);
|
||||
border-bottom: 1px solid var(--prev-border-color-lighter);
|
||||
|
||||
.back-btn {
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
color: var(--prev-color-text-primary);
|
||||
font-size: 14px;
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: var(--prev-color-primary-light-1);
|
||||
color: var(--prev-color-primary);
|
||||
}
|
||||
|
||||
i {
|
||||
@ -661,32 +678,33 @@ function searchTheme() {
|
||||
.detail-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
border-left: 1px solid #eee;
|
||||
color: var(--prev-color-text-regular);
|
||||
border-left: 1px solid var(--prev-border-color-lighter);
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-body {
|
||||
height: calc(100vh - 100px);
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
background: #fff;
|
||||
padding: 0 20px 0 24px !important;
|
||||
background: var(--prev-bg-white);
|
||||
padding: 0 20px 24px 24px;
|
||||
|
||||
.detail-top {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
background: var(--prev-bg-white);
|
||||
padding: 24px 0 20px 0;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
border-bottom: 1px solid var(--prev-border-color-lighter);
|
||||
|
||||
.detail-preview-main {
|
||||
width: 180px;
|
||||
height: 210px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
margin-right: 24px;
|
||||
border: 1px solid #eeeeee;
|
||||
border: 1px solid var(--prev-border-color-lighter);
|
||||
img {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
@ -702,16 +720,15 @@ function searchTheme() {
|
||||
.info-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
color: var(--prev-color-text-regular);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.info-desc {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 30px;
|
||||
color: #888;
|
||||
color: var(--prev-color-text-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -720,7 +737,7 @@ function searchTheme() {
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
color: var(--prev-color-text-regular);
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
@ -733,14 +750,21 @@ function searchTheme() {
|
||||
margin-right: 29px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.image-label {
|
||||
font-size: 12px;
|
||||
color: var(--prev-color-text-secondary);
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.phone-mockup {
|
||||
width: 214px;
|
||||
height: 380px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
background: var(--prev-bg-white);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border: 1px solid #eeeeee;
|
||||
border: 1px solid var(--prev-border-color-lighter);
|
||||
.preview-image {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
@ -752,7 +776,7 @@ function searchTheme() {
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
margin-top: 70px;
|
||||
color: rgba(153, 153, 153, 1);
|
||||
color: var(--prev-color-text-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
@ -762,8 +786,8 @@ function searchTheme() {
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
text-align: center;
|
||||
background: #f9f9f9;
|
||||
border-radius: 8px 8px 8px 8px;
|
||||
background: var(--prev-bg-color);
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
@ -783,10 +807,36 @@ function searchTheme() {
|
||||
|
||||
.qrcode-text {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
color: var(--prev-color-text-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
/* 弹窗壳层覆盖(非 scoped):append-to-body 弹窗 teleport 到 body 后
|
||||
脱离组件样式作用域,scoped :deep 无法命中,必须用业务前缀全局类 */
|
||||
.theme-dialog {
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
|
||||
/* header 内边距归零,留白由内部 .dialog-header(15px 24px)提供,
|
||||
避免与全局 .el-dialog__header 的 15px 叠加成 30px 双重边距 */
|
||||
.el-dialog__header {
|
||||
padding: 0 !important;
|
||||
border-bottom: 1px solid var(--prev-border-color-lighter);
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 0 !important;
|
||||
/* 放开全局 720px 上限,与 top:5vh 匹配,滚动交给内部网格/详情区 */
|
||||
max-height: calc(100vh - 100px);
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<el-button icon="el-icon-view" @click="$emit('preview')">预览</el-button>
|
||||
<el-button icon="View" @click="$emit('preview')">预览</el-button>
|
||||
<el-button v-if="!isMicroPage" @click="$emit('save-template')">另存主题</el-button>
|
||||
<el-button @click="$emit('save')">保存</el-button>
|
||||
<el-button type="primary" @click="$emit('save-close')">保存并关闭</el-button>
|
||||
|
||||
@ -106,11 +106,7 @@
|
||||
<div class="main-content">
|
||||
<div class="filters-header">
|
||||
<div class="search-box">
|
||||
<el-input
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入主题名称"
|
||||
prefix-icon="el-icon-search"
|
||||
></el-input>
|
||||
<el-input v-model="searchKeyword" placeholder="请输入主题名称" prefix-icon="Search"></el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -185,8 +185,11 @@ function setColumnsMenuHighlight(path) {
|
||||
watch(
|
||||
() => themeConfigStore.themeConfig.columnsAsideStyle,
|
||||
(val) => {
|
||||
val === 'columnsRound' ? (difference.value = 3) : (difference.value = 0);
|
||||
// 圆角滑块高 44px(项高 50px),top 下移 3px 使滑块在项内垂直居中;卡片滑块顶满 50px 项高,无需偏移。
|
||||
// 设置面板 radio 下发 kebab-case(columns-round/columns-card),原驼峰比较 columnsRound 永不匹配,一并修正
|
||||
val === 'columns-round' ? (difference.value = 3) : (difference.value = 0);
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// 监听路由的变化
|
||||
@ -222,6 +225,8 @@ watch(
|
||||
color: var(--prev-bg-columnsMenuBarColor);
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
/* 一级菜单图标统一 16px:iconfont 菜单图标组件默认 16px,EP 图标无 .el-menu 上下文会回落 14px */
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
@ -260,11 +265,11 @@ watch(
|
||||
text-decoration: none;
|
||||
color: var(--prev-bg-columnsMenuBarColor);
|
||||
}
|
||||
/* 悬停反馈:以菜单文字色衍生 8% 半透明底,深/浅主题自动适配;不占用选中态主题蓝 */
|
||||
&:hover {
|
||||
background: color-mix(in srgb, var(--prev-bg-columnsMenuBarColor) 8%, transparent);
|
||||
}
|
||||
}
|
||||
// li:hover {
|
||||
// background: var(--prev-color-primary);
|
||||
// color: var(--prev-bg-columnsMenuBarColor);
|
||||
// }
|
||||
.layout-columns {
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
@ -274,18 +279,19 @@ watch(
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* 圆角选中滑块:项高 50px 内上下各留 3px、左右各留 5px,圆角 6px 与全站控件圆角一致;卡片风格由 .columns-card 覆盖回全宽直角 */
|
||||
.columns-round {
|
||||
background: var(--prev-color-primary);
|
||||
// color: var(--prev-color-text-white);
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 2px;
|
||||
height: 50px;
|
||||
width: 65px;
|
||||
top: 3px;
|
||||
height: 44px;
|
||||
width: calc(100% - 10px);
|
||||
transform: translateX(-50%);
|
||||
z-index: 0;
|
||||
transition: 0.3s ease-in-out;
|
||||
border-radius: 5px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.columns-card {
|
||||
@extend .columns-round;
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
v-model="menuQuery"
|
||||
:fetch-suggestions="menuSearch"
|
||||
:placeholder="$t('message.user.searchPlaceholder')"
|
||||
prefix-icon="el-icon-search"
|
||||
prefix-icon="Search"
|
||||
ref="layoutMenuAutocompleteRef"
|
||||
@select="onHandleSelect"
|
||||
@blur="onSearchBlur"
|
||||
|
||||
@ -526,7 +526,7 @@ function onSetLayout(layout) {
|
||||
}
|
||||
themeConfigStore.themeConfig.layout = layout;
|
||||
themeConfigStore.themeConfig.isDrawer = false;
|
||||
themeConfigStore.themeConfig.columnsAsideStyle = 'columns-card';
|
||||
// 高亮风格(columnsAsideStyle)不随布局切换重置,保留用户选择;默认值唯一真源在 store/module/themeConfig.js
|
||||
setLocalTheme(themeConfigStore.themeConfig.themeStyle);
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ import * as tools from '@/libs/tools';
|
||||
import timeOptions from '@/libs/timeOptions';
|
||||
|
||||
// UI 框架
|
||||
import ElementPlus from 'element-plus';
|
||||
import ElementPlus, { ElMessage } from 'element-plus';
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||
import 'element-plus/dist/index.css';
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
|
||||
@ -75,6 +75,20 @@ const app = createApp(App);
|
||||
window.Vue = Vue;
|
||||
window.ElementPlus = ElementPlus;
|
||||
|
||||
// ---- ElMessage 防刷屏:登录过期等场景下多个并发请求同时失败,各页面 catch 各弹一条相同提示。
|
||||
// 为类型方法统一注入 grouping,由 Element Plus 把相同内容合并为一条并显示重复计数;
|
||||
// 内容为 VNode 时不支持合并,原样透传。 ----
|
||||
['success', 'warning', 'info', 'error'].forEach((type) => {
|
||||
const original = ElMessage[type].bind(ElMessage);
|
||||
ElMessage[type] = (options) => {
|
||||
const message = typeof options === 'string' ? options : options?.message;
|
||||
if (typeof message === 'string' && message) {
|
||||
return original(typeof options === 'string' ? { message, grouping: true } : { ...options, grouping: true });
|
||||
}
|
||||
return original(options);
|
||||
};
|
||||
});
|
||||
|
||||
// ---- 过渡兼容层:Vue2 时代的 this.bus($on/$off/$emit 转发到 mitt 总线) ----
|
||||
app.config.globalProperties.bus = {
|
||||
$on: (type, fn) => bus.on(type, fn),
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<el-card :bordered="false" shadow="never">
|
||||
<div class="card-title">
|
||||
<el-avatar
|
||||
icon="el-icon-user-solid"
|
||||
icon="UserFilled"
|
||||
style="color: var(--prev-color-primary); background-color: #e6f7ff"
|
||||
></el-avatar>
|
||||
<h4 class="ivu-pl-8">用户</h4>
|
||||
@ -23,7 +23,7 @@
|
||||
<el-card :bordered="false" shadow="never" class="dashboard-console-visit">
|
||||
<div class="card-title">
|
||||
<el-avatar
|
||||
icon="el-icon-s-marketing"
|
||||
icon="DataAnalysis"
|
||||
style="color: var(--prev-color-primary); background-color: #e6f7ff"
|
||||
></el-avatar>
|
||||
<h4 class="ivu-pl-8">购买用户统计</h4>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<el-row justify="center" align="middle">
|
||||
<el-col :span="8" class="card-title">
|
||||
<el-avatar
|
||||
icon="el-icon-s-marketing"
|
||||
icon="DataAnalysis"
|
||||
style="color: var(--prev-color-primary); background-color: #e6f7ff"
|
||||
></el-avatar>
|
||||
<h4 class="ivu-pl-8">订单</h4>
|
||||
|
||||
@ -7,11 +7,12 @@
|
||||
<div class="mcp-hero-title">MCP 服务管理</div>
|
||||
<div class="mcp-hero-sub">安装 MCP 服务,为 AI Agent 扩展更多工具能力</div>
|
||||
</div>
|
||||
<el-button type="primary" icon="el-icon-setting" v-db-click @click="openEditor()">配置 MCP</el-button>
|
||||
<!-- icon prop 需传全局注册的 EP 图标名(PascalCase);el-icon-* 字符串不会解析成组件 -->
|
||||
<el-button type="primary" icon="Setting" v-db-click @click="openEditor()">配置 MCP</el-button>
|
||||
</div>
|
||||
|
||||
<div class="mcp-toolbar">
|
||||
<el-input v-model="keyword" placeholder="搜索 MCP" prefix-icon="el-icon-search" clearable class="mcp-search" />
|
||||
<el-input v-model="keyword" placeholder="搜索 MCP" prefix-icon="Search" clearable class="mcp-search" />
|
||||
</div>
|
||||
|
||||
<div class="mcp-section">
|
||||
@ -75,7 +76,13 @@
|
||||
尚未同步工具,点击 <i class="el-icon-refresh" /> 拉取远端工具清单。
|
||||
</div>
|
||||
<div v-else class="mcp-tools">
|
||||
<el-tooltip v-for="tool in row.tools" :key="tool.name" :content="toolTip(tool)" placement="top">
|
||||
<el-tooltip
|
||||
v-for="tool in row.tools"
|
||||
:key="tool.name"
|
||||
:content="toolTip(tool)"
|
||||
placement="top"
|
||||
popper-class="ai-mcp-tool-tip"
|
||||
>
|
||||
<span class="tool-chip mono">{{ tool.label || tool.name }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
@ -609,3 +616,11 @@ function removeServer(row) {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
/* 工具提示 popper 挂载在 body 下,scoped 样式无法命中,用专用类全局限定宽度 */
|
||||
.ai-mcp-tool-tip {
|
||||
max-width: 420px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
Skill 以 Markdown 文件存储,Agent 对话时按选择注入上下文(Markdown 指南、流程说明等)。
|
||||
</div>
|
||||
</div>
|
||||
<el-button type="primary" v-db-click @click="openEditor()">新建 Skill</el-button>
|
||||
<el-button type="primary" icon="Plus" v-db-click @click="openEditor()">新建 Skill</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :data="list" v-loading="loading" row-key="key">
|
||||
@ -41,6 +41,7 @@
|
||||
<span class="table-link danger" @click="removeSkill(scope.row)">删除</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>暂无 Skill,点击右上角「新建 Skill」创建</template>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
@ -51,6 +52,7 @@
|
||||
direction="rtl"
|
||||
size="60%"
|
||||
append-to-body
|
||||
class="ai-skill-drawer"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div class="drawer-body">
|
||||
@ -122,17 +124,17 @@
|
||||
direction="rtl"
|
||||
size="60%"
|
||||
append-to-body
|
||||
class="ai-skill-drawer"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div class="drawer-body">
|
||||
<div class="toolbar">
|
||||
<div class="toolbar-tip" style="margin-top: 0">
|
||||
附属资料不随对话注入,Agent 判断需要更完整资料时按需加载;文件为 .md 格式(SKILL.md 与 EXAMPLES.md
|
||||
为保留名)。
|
||||
</div>
|
||||
<el-button type="primary" size="small" icon="el-icon-plus" v-db-click @click="openAttachmentEditor()"
|
||||
>新建附件</el-button
|
||||
>
|
||||
<div class="attach-tip">
|
||||
附属资料不随对话注入,Agent 判断需要更完整资料时按需加载;文件为 .md 格式(SKILL.md 与 EXAMPLES.md
|
||||
为保留名)。
|
||||
</div>
|
||||
<div class="attach-toolbar">
|
||||
<span class="attach-count">共 {{ attachmentList.length }} 个文件</span>
|
||||
<el-button type="primary" icon="Plus" v-db-click @click="openAttachmentEditor()">新建附件</el-button>
|
||||
</div>
|
||||
<el-table :data="attachmentList" v-loading="attachmentLoading" row-key="file">
|
||||
<el-table-column label="文件名" min-width="200">
|
||||
@ -155,6 +157,7 @@
|
||||
<span class="table-link danger" @click="removeAttachment(scope.row)">删除</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>暂无附属资料,点击右上角「新建附件」添加</template>
|
||||
</el-table>
|
||||
</div>
|
||||
<template #footer>
|
||||
@ -171,6 +174,7 @@
|
||||
direction="rtl"
|
||||
size="60%"
|
||||
append-to-body
|
||||
class="ai-skill-drawer"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div class="drawer-body">
|
||||
@ -567,18 +571,18 @@ onMounted(() => {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.toolbar-title {
|
||||
color: #303133;
|
||||
color: var(--prev-color-text-regular);
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.toolbar-tip,
|
||||
.muted {
|
||||
margin-top: 6px;
|
||||
color: #909399;
|
||||
color: var(--prev-color-text-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
.skill-name {
|
||||
color: #303133;
|
||||
color: var(--prev-color-text-regular);
|
||||
font-weight: 600;
|
||||
}
|
||||
.mono {
|
||||
@ -599,11 +603,11 @@ onMounted(() => {
|
||||
opacity: 0.8;
|
||||
}
|
||||
&.danger {
|
||||
color: #f56c6c;
|
||||
color: var(--prev-color-danger);
|
||||
}
|
||||
}
|
||||
.danger {
|
||||
color: #f56c6c;
|
||||
color: var(--prev-color-danger);
|
||||
}
|
||||
.content-editor :deep(.el-textarea__inner) {
|
||||
height: max(calc(100vh - 310px), 520px);
|
||||
@ -613,11 +617,37 @@ onMounted(() => {
|
||||
line-height: 1.7;
|
||||
}
|
||||
.drawer-body {
|
||||
padding: 0 24px 10px;
|
||||
/* 左右留白由 .ai-skill-drawer 全局规则(16px)提供,此处只补底部间距,避免双重内边距 */
|
||||
padding: 0 0 10px;
|
||||
}
|
||||
.ai-inline-tip {
|
||||
margin-left: 10px;
|
||||
color: #909399;
|
||||
color: var(--prev-color-text-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
/* 附属资料抽屉:说明独立成行,操作行(计数 + 新建按钮)右对齐,与卡片页工具栏同构 */
|
||||
.attach-tip {
|
||||
margin-bottom: 14px;
|
||||
color: var(--prev-color-text-secondary);
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.attach-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.attach-count {
|
||||
color: var(--prev-color-text-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
/* 三个抽屉均 append-to-body 挂载在 body 下,scoped 样式无法命中,
|
||||
用业务前缀类收窄 body 水平内边距(全局 35px 对 60% 宽抽屉偏大) */
|
||||
.ai-skill-drawer .el-drawer__body {
|
||||
padding: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<div class="task-hero-title">自动化任务</div>
|
||||
<div class="task-hero-sub">让 AI 按计划无人值守执行指令并推送结果(如每日经营日报)</div>
|
||||
</div>
|
||||
<el-button type="primary" icon="el-icon-plus" v-db-click @click="openEditor()">新建任务</el-button>
|
||||
<el-button type="primary" icon="Plus" v-db-click @click="openEditor()">新建任务</el-button>
|
||||
</div>
|
||||
|
||||
<div class="task-section">
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
<div>
|
||||
<div class="i-layout-page-header header-title">
|
||||
<div class="fl_header">
|
||||
<el-button class="btn-back" icon="el-icon-arrow-left" type="text" v-db-click @click="$router.go(-1)"
|
||||
>返回</el-button
|
||||
>
|
||||
<el-button class="btn-back" icon="ArrowLeft" type="text" v-db-click @click="$router.go(-1)">返回</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<span class="ivu-page-header-title">{{ $route.query.lottery_id ? '编辑' : '新增' }}抽奖活动</span>
|
||||
</div>
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
<div>
|
||||
<div class="i-layout-page-header header-title">
|
||||
<div class="fl_header">
|
||||
<el-button class="btn-back" icon="el-icon-arrow-left" type="text" v-db-click @click="$router.go(-1)"
|
||||
>返回</el-button
|
||||
>
|
||||
<el-button class="btn-back" icon="ArrowLeft" type="text" v-db-click @click="$router.go(-1)">返回</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<span class="ivu-page-header-title">{{ $route.meta.title }}</span>
|
||||
</div>
|
||||
|
||||
@ -271,4 +271,11 @@ function brokerageSetUp() {
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use '../productAdd.scss' as *;
|
||||
|
||||
.tip {
|
||||
width: 100%;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
></WangEditor>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6" style="width: 33%">
|
||||
<el-col :span="8">
|
||||
<div class="ifam">
|
||||
<div class="content" v-html="content"></div>
|
||||
</div>
|
||||
@ -57,4 +57,16 @@ function getEditorContent(val) {
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use '../productAdd.scss' as *;
|
||||
|
||||
/* 编辑器整体与右侧手机预览(644px)等高:工具栏自适应行数,编辑区占满剩余高度,底部对齐 */
|
||||
:deep(.wang-editor) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 644px;
|
||||
}
|
||||
|
||||
:deep(.editor-content) {
|
||||
flex: 1;
|
||||
height: auto !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- <div class="i-layout-page-header header-title">
|
||||
<span class="ivu-page-header-title">{{ $route.meta.title }}</span>
|
||||
</div> -->
|
||||
<pages-header ref="pageHeader" :title="$route.meta.title"></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-card shadow="never" class="ivu-mt mt16">
|
||||
<div class="flex-wrapper">
|
||||
<!-- :src="iframeUrl" -->
|
||||
<div>
|
||||
<iframe class="iframe-box" :src="iframeUrl" frameborder="0" ref="iframe"></iframe>
|
||||
<div v-if="iframeUrl" class="preview-box">
|
||||
<iframe class="iframe-box" :src="iframeUrl" frameborder="0"></iframe>
|
||||
<div class="mask"></div>
|
||||
</div>
|
||||
<div v-else class="preview-box preview-empty">
|
||||
<el-empty description="未获取到 H5 商城地址,无法预览">
|
||||
<div class="empty-tips">
|
||||
请在 系统设置 → 系统配置 中正确配置站点网址(site_url); 如需指向独立 H5 调试地址,可在
|
||||
frontend/admin/.env.dev 中配置 VITE_APP_H5_URL
|
||||
</div>
|
||||
</el-empty>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<div class="content">
|
||||
@ -66,27 +70,18 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { routineDownload, routineInfo } from '../../../api';
|
||||
import Setting from '@/setting';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'routineTemplate' });
|
||||
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const grid = ref({
|
||||
xl: 7,
|
||||
lg: 7,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
});
|
||||
const iframeUrl = ref(`${Setting.h5BaseURL || location.origin}/pages/index/index?mdType=iframeWindow`);
|
||||
// H5 预览地址:接口返回站点配置后按优先级组装
|
||||
// 1. 前端环境变量 VITE_APP_H5_URL(显式指定,如独立 uni-app dev server)
|
||||
// 2. 后端系统配置站点网址 site_url(默认形态,H5 部署在 backend/public)
|
||||
// 3. 当前域名(兜底)
|
||||
const iframeUrl = ref('');
|
||||
const is_live = ref(1);
|
||||
const pageData = ref({
|
||||
code: '',
|
||||
@ -98,6 +93,9 @@ const pageData = ref({
|
||||
|
||||
routineInfo().then((res) => {
|
||||
pageData.value = res.data;
|
||||
iframeUrl.value = `${
|
||||
Setting.h5BaseURL || res.data.site_url || location.origin
|
||||
}/pages/index/index?mdType=iframeWindow`;
|
||||
});
|
||||
|
||||
function downLoad() {
|
||||
@ -126,7 +124,7 @@ function downLoadCode(url) {
|
||||
var url = canvas.toDataURL(); //得到图片的base64编码数据
|
||||
var a = document.createElement('a'); // 生成一个a元素
|
||||
var event = new MouseEvent('click'); // 创建一个单击事件
|
||||
a.download = name || 'photo'; // 设置图片名称
|
||||
a.download = '小程序码'; // 设置图片名称
|
||||
a.href = url; // 将生成的URL设置为a.href属性
|
||||
a.dispatchEvent(event); // 触发a的单击事件
|
||||
};
|
||||
@ -147,6 +145,23 @@ function downLoadCode(url) {
|
||||
display: flex;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.preview-box {
|
||||
position: relative;
|
||||
width: 312px;
|
||||
}
|
||||
.preview-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
.empty-tips {
|
||||
max-width: 260px;
|
||||
font-size: 12px;
|
||||
color: var(--prev-color-text-secondary);
|
||||
line-height: 1.8;
|
||||
text-align: center;
|
||||
}
|
||||
.iframe-box {
|
||||
width: 312px;
|
||||
height: 550px;
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
backgroundSize: '100% 100%',
|
||||
}"
|
||||
>
|
||||
<el-button type="error" icon="el-icon-delete" v-db-click @click="del(i)" v-show="isDel"></el-button>
|
||||
<el-button type="error" icon="Delete" v-db-click @click="del(i)" v-show="isDel"></el-button>
|
||||
</div>
|
||||
<span class="news_sp">{{ item.title }}</span>
|
||||
</div>
|
||||
@ -34,7 +34,7 @@
|
||||
<div class="news_cent_img ivu-mr-8">
|
||||
<img :src="item.image_input ? item.image_input : baseImg" />
|
||||
</div>
|
||||
<el-button type="error" icon="el-icon-delete" v-db-click @click="del(i)"></el-button>
|
||||
<el-button type="error" icon="Delete" v-db-click @click="del(i)"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="acea-row row-center-wrapper">
|
||||
|
||||
@ -185,13 +185,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-button
|
||||
v-else
|
||||
class="upload-select"
|
||||
type="dashed"
|
||||
icon="el-icon-plus"
|
||||
@click="modalPicTap(1)"
|
||||
></el-button>
|
||||
<el-button v-else class="upload-select" type="dashed" icon="Plus" @click="modalPicTap(1)"></el-button>
|
||||
<p class="tip">建议尺寸:80px*30px,若未上传则为空白</p>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序:">
|
||||
|
||||
@ -91,7 +91,7 @@
|
||||
<el-form ref="modelForm" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item prop="base_url">
|
||||
<div class="base-url-head">
|
||||
<span class="base-url-label">自定义请求地址<i class="required-star">*</i></span>
|
||||
<span class="base-url-label"><i class="required-star">*</i>自定义请求地址</span>
|
||||
<span class="base-url-switch">
|
||||
<i class="el-icon-link" />
|
||||
<span>完整 URL</span>
|
||||
@ -463,14 +463,16 @@ onMounted(() => {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin-bottom: 4px;
|
||||
/* 标签(0) + 提示(6px) 合计 8px,对齐 EP top 标签与内容的默认间距 */
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.base-url-label {
|
||||
color: var(--prev-color-text-primary);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
/* 与全局 .el-form-item__label(12px / text-regular)对齐,避免比其他标签大一圈 */
|
||||
color: var(--prev-color-text-regular);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
.required-star {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
color: var(--prev-color-danger);
|
||||
font-style: normal;
|
||||
}
|
||||
@ -480,7 +482,7 @@ onMounted(() => {
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: var(--prev-color-text-primary);
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
i {
|
||||
color: var(--prev-color-text-secondary);
|
||||
}
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
<div>
|
||||
<div class="i-layout-page-header header-title">
|
||||
<div class="fl_header">
|
||||
<el-button class="btn-back" icon="el-icon-arrow-left" type="text" v-db-click @click="$router.go(-1)"
|
||||
>返回</el-button
|
||||
>
|
||||
<el-button class="btn-back" icon="ArrowLeft" type="text" v-db-click @click="$router.go(-1)">返回</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<span class="ivu-page-header-title">{{ $route.meta.title }}</span>
|
||||
</div>
|
||||
|
||||
@ -27,61 +27,66 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-for="(item, index) in formValidate.typelist" :key="index">
|
||||
<el-col v-bind="grid">
|
||||
<el-form-item
|
||||
:label="'字段' + (index + 1) + ':'"
|
||||
label-width="90px"
|
||||
:prop="'typelist.' + index + '.name.value'"
|
||||
:rules="{ required: true, message: '请输入字段名称:姓名', trigger: 'blur' }"
|
||||
<el-row :gutter="20">
|
||||
<el-col v-bind="grid">
|
||||
<el-form-item
|
||||
:label="'字段' + (index + 1) + ':'"
|
||||
label-width="90px"
|
||||
:prop="'typelist.' + index + '.name.value'"
|
||||
:rules="{ required: true, message: '请输入字段名称:姓名', trigger: 'blur' }"
|
||||
>
|
||||
<el-input v-model="item.name.value" placeholder="字段名称:姓名"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-bind="grid">
|
||||
<el-form-item
|
||||
label-width="0"
|
||||
:prop="'typelist.' + index + '.title.value'"
|
||||
:rules="{ required: true, message: '请输入字段配置名', trigger: 'blur' }"
|
||||
>
|
||||
<el-input v-model="item.title.value" placeholder="字段配置名:name"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-bind="grid">
|
||||
<el-form-item
|
||||
label-width="0"
|
||||
:prop="'typelist.' + index + '.type.value'"
|
||||
:rules="{ required: true, message: '请选择字段类型', trigger: 'change' }"
|
||||
>
|
||||
<el-select placeholder="字段类型" v-model="item.type.value">
|
||||
<el-option value="input">文本框</el-option>
|
||||
<el-option value="textarea">多行文本框</el-option>
|
||||
<el-option value="radio">单选框</el-option>
|
||||
<el-option value="checkbox">多选框</el-option>
|
||||
<el-option value="select">下拉选择</el-option>
|
||||
<el-option value="upload">单图</el-option>
|
||||
<el-option value="uploads">多图</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-bind="gridBtn">
|
||||
<el-form-item label-width="0">
|
||||
<el-button icon="Delete" v-db-click @click="delGroup(index)"></el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col
|
||||
v-if="item.type.value === 'radio' || item.type.value === 'checkbox' || item.type.value === 'select'"
|
||||
:span="24"
|
||||
>
|
||||
<el-input v-model="item.name.value" placeholder="字段名称:姓名"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-bind="grid" class="goupBox">
|
||||
<el-form-item
|
||||
label-width="0"
|
||||
:prop="'typelist.' + index + '.title.value'"
|
||||
:rules="{ required: true, message: '请输入字段配置名', trigger: 'blur' }"
|
||||
>
|
||||
<el-input v-model="item.title.value" placeholder="字段配置名:name"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-bind="grid" prop="type" class="goupBox">
|
||||
<el-form-item
|
||||
:prop="'typelist.' + index + '.type.value'"
|
||||
:rules="{ required: true, message: '请选择字段类型', trigger: 'change' }"
|
||||
label-width="0"
|
||||
>
|
||||
<el-select placeholder="字段类型" v-model="item.type.value">
|
||||
<el-option value="input">文本框</el-option>
|
||||
<el-option value="textarea">多行文本框</el-option>
|
||||
<el-option value="radio">单选框</el-option>
|
||||
<el-option value="checkbox">多选框</el-option>
|
||||
<el-option value="select">下拉选择</el-option>
|
||||
<el-option value="upload">单图</el-option>
|
||||
<el-option value="uploads">多图</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-button icon="el-icon-delete" v-db-click @click="delGroup(index)"></el-button>
|
||||
<!-- <el-col span="1"> </el-col> -->
|
||||
<el-col
|
||||
:span="24"
|
||||
v-if="item.type.value === 'radio' || item.type.value === 'checkbox' || item.type.value === 'select'"
|
||||
>
|
||||
<el-form-item
|
||||
:prop="'typelist.' + index + '.param.value'"
|
||||
:rules="{ required: true, message: '请输入参数方式', trigger: 'blur' }"
|
||||
>
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
:placeholder="item.param.placeholder"
|
||||
v-model="item.param.value"
|
||||
style="width: 90%"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-form-item
|
||||
:prop="'typelist.' + index + '.param.value'"
|
||||
:rules="{ required: true, message: '请输入参数方式', trigger: 'blur' }"
|
||||
>
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
:placeholder="item.param.placeholder"
|
||||
v-model="item.param.value"
|
||||
style="width: 90%"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-form-item>
|
||||
@ -134,6 +139,13 @@ const grid = {
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const gridBtn = {
|
||||
xl: 3,
|
||||
lg: 3,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const modals = ref(false);
|
||||
const modal12 = ref(false);
|
||||
const ruleValidate = {
|
||||
@ -235,7 +247,4 @@ defineExpose({ modals, fromData });
|
||||
.cur {
|
||||
cursor: pointer;
|
||||
}
|
||||
.goupBox :deep(.ivu-form-item-content) {
|
||||
margin-left: 43px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -80,7 +80,7 @@ export const useThemeConfigStore = defineStore(
|
||||
// 主页面切换动画:可选值"<slide-right|slide-left|opacitys>",默认 slide-right
|
||||
animation: 'opacitys',
|
||||
// 分栏高亮风格:可选值"<columns-round|columns-card>",默认 columns-round
|
||||
columnsAsideStyle: 'columns-card',
|
||||
columnsAsideStyle: 'columns-round',
|
||||
// 分栏布局风格:可ƒ选值"<columns-horizontal|columns-vertical>",默认 columns-horizontal
|
||||
columnsAsideLayout: 'columns-vertical',
|
||||
|
||||
|
||||
@ -394,6 +394,14 @@
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
// 二级菜单展开抖动修复:EP 的 ElCollapseTransition 动画在 overflow visible/hidden 间切换,
|
||||
// .columns-round 给菜单项加的 margin 在 visible 时向外塌陷、hidden 时被包含,导致 scrollHeight
|
||||
// 测量值与实际内容高度不一致,动画起止瞬间高度突变(肉眼可见的上跳)。
|
||||
// flow-root 让内联子菜单始终成为 BFC,margin 全程被包含,三者高度一致;间隙视觉不变。
|
||||
.layout-aside .el-menu .el-menu--inline {
|
||||
display: flow-root;
|
||||
}
|
||||
|
||||
// 菜单收起时鼠标经过背景颜色/字体颜色
|
||||
.el-menu--vertical {
|
||||
background: var(--prev-bg-menuBar) !important;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user