我先说下总结,从使用上来看,jeecms功能看着很多,但是核心功能做的不彻底,不够强,只能应付一般性使用,复杂的要求就比较难实现,甚至还得自己改代码。
一、部署包下载
二、源代码下载
三、文档下载
这三个的下载都在官方论坛的帖子中,需要先注册并回帖。正版系统和正版源码等购买后官方会提供。
四、源码运行
源代码运行需要先配置好数据库,数据库需要自己从部署包中获取到脚本,然后再执行。我用的是centos下的mysql数据库,源代码运行和安装部署运行都报错,查找问题发现数据库中的所有QRTZ表的表名大小写问题。在linux下mysql默认是区分大小写的。脚本中的表名都是小写的,把表名字都改成大写就可以了。
当前免费版后台首页是 http://localhost:8083/jeecms/index.html , 网站的首页是 http://localhost:8083 需要后台对站点进行设置,设置成localhost。初始登录账号 system,密码 123456
五、安装部署
安装部署中碰到了首页打不开的问题,或者说首页打开就是tomcat的首页。去掉tomcat配置文件中的首页的定义解决。配置完成后同样需要进入后台后对站点进行设置。
六、系统的使用
主要使用的功能有如下几个:
- 系统/模型管理/内容模型管理:创建详情页需要的数据,这里制作的表单也就是编辑人员发布信息的表单页面。我在这里创建了“解决方案“模型,里面增加了banner字段。解决方案栏目下的所有子页面都用这个模型。
- 配置/模板管理,模板维护在这里。
- 栏目管理,我在这里创建了一二级栏目结构。一级栏目“首页“、”解决方案“、”产品“、”服务“等,按照导航的结构来做的定义。其中二级栏目定义了模板,使用的是solution.html模板,这样点击二级栏目链接跳转的页面会使用这个模板来生成。另外栏目需要设置模型。
- 内容管理,对对应栏目发布内容。
七、模板说明
模板常用的是内容模板和栏目模板,分别用于显示栏目页面和内容页面。在栏目模板中,我已经完成了首页的header的菜单导航部分。采用的是把导航设置成了两级栏目的方式,从菜单导航点进去的各个方案产品等页面都是内容页。
一些代码说明:
<div id="channelIds" ref="channelIds" style="display: none;">
[@cms_channel_list siteId='1']
[#list tag_list as a]
<span>${a.id}</span>
[/#list]
[/@cms_channel_list]
</div>
上面的代码是获取所有一级频道列表,网站最上面的一条,下面的代码是生成弹出的菜单导航代码。根据导航的结构,做了三层循环。代码参见portal-html项目的index-1.html页。
[@cms_channel_list siteId='1']
[#list tag_list as a]
[@cms_channel id='${a.id}']
<div class="base-header-menu" v-if="showMenu && iSelectMenuIndex == ${a.id}" @click="clickBlack">
<div class="menu-container_" @mouseleave="clickBlack" @click.stop="clickContent">
<div class="left animated slideInLeft" >
<div class="content-container block-anim-left-to-right">
<div class="title">
${tag_bean.name}
</div>
<div class="description">
${tag_bean.description!""}
</div>
</div>
</div>
<div class="right block-anim-right-to-left animated slideInRight">
<div
:class="{
'content-container': iSelectMenuIndex == channelIds[1] || iSelectMenuIndex == channelIds[3],
'content-container2': iSelectMenuIndex == channelIds[2],
'content-container3': iSelectMenuIndex == channelIds[4]}">
[@cms_channel_list siteId='1' parentId='${tag_bean.id}']
[#list tag_list as b]
<div class="list">
<div class="list-title">${b.name}</div>
<div class="list-item-container">
<!-- <div class="list-item" v-for="(child, child_index) in item.child"
:key="child.cn" @click="clickDescription(index, child_index)">
{{ child.cn }}
</div> -->
[@cms_content_list count='8' channelId='${b.id}']
[#list tag_list as a]
<a class="list-item"
href="${a.url}">
${a.title!}
</a>
[/#list]
[/@cms_content_list]
</div>
</div>
[/#list]
[/@cms_channel_list]
</div>
<img src="${tag_bean.iconUrl}" class="icon" />
</div>
<!-- <div class="right block-anim-right-to-left animated slideInRight">
<div :class="{
'content-container': iSelectMenuIndex == 1 || iSelectMenuIndex == 3,
'content-container2': iSelectMenuIndex == 2,
'content-container3': iSelectMenuIndex == 4}">
<div class="list" v-for="(item, index) in header_tab_title[iSelectMenuIndex].list"
:key="item.cn">
<div class="list-title">{{ item.cn }}</div>
<div class="list-item-container">
<div class="list-item" v-for="(child, child_index) in item.child"
:key="child.cn" @click="clickDescription(index, child_index)">
{{ child.cn }}
</div>
</div>
</div>
</div>
<img src="" class="icon" />
</div> -->
</div>
</div>
[/@cms_channel]
[/#list]
[/@cms_channel_list]
Content/solution.html模板中,主要代码如下,参看项目源代码中的solution-1.html
<#assign json2=content.txtAttrCleanHtml.content?eval/>
<#list json2 as block>
<div class="content-base">
<#if block.blockType == 'description'>
<div :class="{ 'product-word-base': true, 'font-background': ${(block.background == 'gray') ? string("true","false")} }" v-scroll="'anim-bottom-to-top'">
<div class="description">
<div :class="{
'description-content': true,
'font-bold': ${(block.type == 'bold') ? string("true","false")},
'font-align-center': ${(block.align == 'center') ? string("true","false")},
'font-align-left': ${(block.align != 'center') ? string("true","false")},
'font-width-small': ${(block.size == 'small') ? string("true","false")},
'font-width-normal': ${(block.size == 'normal') ? string("true","false")},
'font-margin-line': ${(block.margin == 'line') ? string("true","false")},
'font-color-gray': ${(block.background == 'gray') ? string("true","false")}
}"
>
<#if block.cn??>
<span>
${block.cn?html}
<#if block.sub_cn??>
<span class="font-small">${block.sub_cn?html}</span>
</#if>
</span>
</#if>
</div>
</div>
</div>
<#elseif block.blockType == 'timeline'>
<div :class="{'product-timeline-base': true, 'gray': ${(block.background == 'gray') ? string('true','false')} }"
v-scroll="'anim-bottom-to-top'"
>
<div class="title">${block.title.cn?html}</div>
<div class="timeline">
<div class="top">
<#list block.timeline as tl>
<#if (tl?index) == 0 || (tl?index) == 2>
<div class="timeline-item-base">
<img src="/images/asset/arrow_top.png" class="arrow" v-if="false" />
<div class="bg">
<div class="title" style="margin-left: 0;">${tl.title.cn?html}</div>
<div class="description">${tl.description.cn?html}</div>
</div>
<img
src="/images/asset/arrow_bottom.png"
class="arrow"
v-if="true"
/>
</div>
</#if>
</#list>
</div>
<img src="/images/asset/scrollbar.png" class="image-bar" />
<div class="bottom">
<#list block.timeline as tl>
<#if (tl?index) == 1 || (tl?index) == 3>
<div class="timeline-item-base">
<img src="/images/asset/arrow_top.png" class="arrow" v-if="true" />
<div class="bg">
<div class="title" style="margin-left: 0;">${tl.title.cn?html}</div>
<div class="description">${tl.description.cn?html}</div>
</div>
<img
src="/images/asset/arrow_bottom.png"
class="arrow"
v-if="false"
/>
</div>
</#if>
</#list>
</div>
</div>
</div>
<#elseif block.blockType == 'menu_bottom'>
<div
:class="{ 'product-swiper-base': true, gray: ${(block.background == 'gray') ? string('true','false')} }">
<div class="menu-container" v-scroll="'anim-bottom-to-top'">
<#list block.menu_bottom as item>
<div
:class="{
'item-2': ${(block.line_count == '2') ? string('true','false')},
'item-3': ${(block.line_count == '3') ? string('true','false')},
'item-4': ${(block.line_count == '4') ? string('true','false')}
}"
>
<div class="solution-detail-container">
<img src="/images/asset/语言康复.png" class="icon" />
<div class="title">${item.title.cn?html}</div>
<div
:class="{ 'description': true, 'description-phone': isphone }"
v-html="item.description.cn"
@click="showDialog"
>${item.description.cn?html}</div>
</div>
</div>
</#list>
</div>
<#if block.contact == 'show'>
<div
v-scroll="'anim-bottom-to-top'"
:class="{
'contact-btn': true
}"
@click="clickContact"
>
联系我们
</div>
</#if>
</div>
</#if>
</div>
</#list>
内容管理中如下做发布,将项目的data.js文件中的cmsData的值拷贝出来,压缩去空格后,录入到内容管理的正文中发布,页面模板通过解析这个json字符串,格式化输出页面内容。
json数据大概是这样的数组
[{
"blockType": "description/timeline/menu_bottom",
"type": "bold",
"align": "center",
"size": "small/normal",
"margin": "line",
"background": "gray",
"cn": "这是文本内容",
"sub_cn": "这是小字部分"
}]
其实让网站维护人员填写json数据不是好办法,最好使用带有提示性的表单来完成维护操作,但是jeecms的表单功能太简单了,没法实现复杂的定制化数据结构,比如我一个页面可能有多个块构成,这些块可能是各种特效效果,每种特效需要的数据项不同,需要设置复杂点的表单来让用户录入数据。当前只能录入json。奇葩的是多行文本只能50字符好像,必须得用自带的正文,而自带的正文录入json会自动html编码化,并且无法使用FreeMarker解码,造成无法实现json数据获取。我把源代码做了些调整,txtAttrCleanHtml 改成了Html解码功能,但是录入的json还是会有问题,说一个空格字符不识别。那我就先用工具把json去空格,然后再录入就没问题了,太曲折。最后总结下jeecms缺点:内容模型不够强,没有数组类型,不知条件显示,比如页面上一个选项关联一个显示块,让表单变动态显示。应对复杂业务场景表单显示效果很差。没有足够好的内容提醒, 没有事件和和基于事件的默认值等。字段长度也很有问题,多行文本最多50字,我没记错的话。