第一部分:规划与准备
在开始编码之前,清晰的规划是成功的一半。
需求分析
一个功能完善的旅游网站通常需要包含以下模块:
- 首页:
- 精Banner轮播(展示热门目的地、特惠产品)
- 热门线路推荐
- 目的地分类展示(如国内游、出境游、周边游)
- 景点/酒店推荐
- 旅游攻略/游记分享
- 友情链接
- 目的地频道:
- 按大洲、国家、省份分类展示目的地。
- 每个目的地详情页,包含介绍、图片、相关线路、相关景点等。
- 线路产品频道: (核心)
- 列表页: 按分类(出境/国内)、主题(亲子/蜜月/探险)、价格、出发地等筛选。
- 详情页: 这是最重要的页面,需要展示:
- 、副标题、价格
- 产品封面图、相册
- 详细行程安排(Day 1, Day 2...)
- 费用包含/不包含
- 预订须知
- 用户评价
- 在线预订表单
- 景点/酒店频道:
景点/酒店的列表和详情页,包含介绍、图片、地址、评分、用户评论等。
- 旅游资讯/攻略频道:
发布旅游相关的新闻、攻略、签证信息等,用于SEO和内容填充。
- 用户中心:
- 注册/登录
- 我的订单
- 我的收藏
- 我的点评
- 关于我们/联系我们页面:
技术准备
- 环境: PHP + MySQL + Apache/Nginx (Dede标准运行环境)
- Dede版本: 建议使用稳定版本,如 DedeCMS V5.7 或 V5.8。
- 代码编辑器: VS Code, Sublime Text 等。
- FTP/SFTP工具: 用于上传文件到服务器。
- 数据库管理工具: 如 phpMyAdmin。
数据库设计 (核心)
这是二次开发的基石,你需要设计合理的 dede_archives (文章表) 和自定义表。
核心思路:
- 内容模型: Dede的核心是“文章”,我们可以创建不同的内容模型来对应不同的内容类型。
- 线路产品: 创建一个名为
line_product的自定义模型。 - 目的地: 创建一个名为
destination的自定义模型。 - 景点/酒店: 创建一个名为
spot_hotel的自定义模型。
- 线路产品: 创建一个名为
以“线路产品”为例,设计自定义表结构 (dede_addonline_product):
| 字段名 | 类型 | 说明 | 备注 |
|---|---|---|---|
aid |
int(11) | 文章ID (主键, 关联dede_archives) | |
price |
decimal(10,2) | 产品价格 | |
duration |
varchar(50) | 行程天数 | 如 "5天4晚" |
start_city |
varchar(100) | 出发城市 | |
line_type |
smallint(6) | 线路类型 | 1:国内游, 2:出境游, 3:周边游 (可做联动类型) |
trip_style |
varchar(255) | 旅行主题 | "亲子,蜜月,探险" (用逗号分隔) |
group_size |
varchar(50) | 成团人数 | 如 "10人成团" |
book_form |
text | 预订表单配置 | 可以用JSON格式存储表单字段,如姓名、电话、人数等,方便前端动态渲染 |
itinerary |
text | 行程安排 | 使用编辑器,支持图文混排 |
fee_include |
text | 费用包含 | |
fee_exclude |
text | 费用不包含 | |
notice |
text | 预订须知 |
创建步骤:
- 进入Dede后台 -> 系统 -> SQL命令行工具。
- 执行
CREATE TABLE语句创建你的自定义表。 - 进入 核心 -> 内容模型管理 -> 模型,填写模型信息,并将模型对应的表指向你刚创建的表。
第二部分:核心功能开发实现
模型与栏目
这是所有开发的前置步骤。
- 添加栏目: 在后台“栏目管理”中,创建“国内游”、“出境游”、“目的地攻略”等顶级栏目。
- 关联模型: 在添加每个栏目时,为其选择正确的“内容模型”。“国内游”栏目选择你创建的
line_product模型。
线路产品列表页开发
假设你的线路列表页模板是 templets/default/line_list.htm。
目标: 显示线路列表,并提供筛选功能。
a. 模板代码 (line_list.htm):
{dede:include filename="head.htm"/}
<div class="main">
<div class="page-title">
<h1>{dede:field.typename/}</h1>
</div>
<!-- 筛选区域 -->
<div class="filter-area">
<form name="search" action="/plus/list.php" method="get">
<input type="hidden" name="tid" value="{dede:field.id/}">
出发地: <input type="text" name="start_city" value="{dede:GET.start_city/}" />
价格区间: <input type="text" name="min_price" value="{dede:GET.min_price/}" /> -
<input type="text" name="max_price" value="{dede:GET.max_price/}" />
<input type="submit" value="筛选" />
</form>
</div>
<!-- 线路列表 -->
<div class="line-list">
{dede:list pagesize='12' titlelen='50'}
<div class="line-item">
<a href="[field:arcurl/]">
<img src="[field:litpic/]" alt="[field:title/]" />
<h2>[field:title/]</h2>
<p class="desc">[field:description function='cn_substr(@me, 100)'/]...</p>
<div class="info">
<span class="price">¥[field:price/]</span>
<span class="duration">[field:duration/]</span>
</div>
</a>
</div>
{/dede:list}
</div>
<!-- 分页 -->
<div class="page-nav">
{dede:pagelist listsize='4' listitem='info,index,end,pre,next,pageno'}
</div>
</div>
{dede:include filename="footer.htm"/}
b. 后台处理 (修改 /plus/list.php):
list.php 默认只处理关键词搜索,我们需要扩展它来处理自定义的筛选条件。
在 list.php 中找到查询语句构建的部分,在 $sql = "SELECT ..." 之前加入你的筛选逻辑:
// ... 其他代码 ...
// 获取GET参数
$start_city = isset($_GET['start_city']) ? trim($_GET['start_city']) : '';
$min_price = isset($_GET['min_price']) ? floatval($_GET['min_price']) : 0;
$max_price = isset($_GET['max_price']) ? floatval($_GET['max_price']) : 0;
// 构建基础查询
// $sql = "SELECT arc.*,tp.typedir,tp.typename,tp.corank,tp.isdefault,tp.defaultname,tp.namerule,
// tp.namerule2,tp.ispart,tp.moresite,tp.siteurl,tp.sitepath
// FROM `dede_archives` arc
// LEFT JOIN `dede_arctype` tp ON tp.id=arc.typeid
// WHERE arc.arcrank > -1 AND arc.typeid='$typeid' ";
$sql = "SELECT arc.*,tp.typedir,tp.typename,tp.corank,tp.isdefault,tp.defaultname,tp.namerule,tp.namerule2,tp.ispart,tp.moresite,tp.siteurl,tp.sitepath,addo.price,addo.duration,addo.start_city
FROM `dede_archives` arc
LEFT JOIN `dede_arctype` tp ON tp.id=arc.typeid
LEFT JOIN `dede_addonline_product` addo ON addo.aid=arc.id
WHERE arc.arcrank > -1 AND arc.typeid='$typeid' ";
// 添加筛选条件
if (!empty($start_city)) {
$sql .= " AND addo.start_city LIKE '%{$start_city}%' ";
}
if ($min_price > 0) {
$sql .= " AND addo.price >= {$min_price} ";
}
if ($max_price > 0) {
$sql .= " AND addo.price <= {$max_price} ";
}
// ... 后续代码保持不变 ...
注意: 修改了JOIN和SELECT部分,以获取自定义表中的字段。
线路产品详情页开发
详情页模板 templets/default/line_article.htm。
目标: 展示完整的线路信息,并提供预订入口。
a. 模板代码 (line_article.htm):
{dede:include filename="head.htm"/}
<div class="main">
<div class="line-detail">
<h1>{dede:field.title/}</h1>
<div class="info-bar">
<span class="price">价格: <strong>¥{dede:field.price/}</strong> 起</span>
<span class="duration">行程: {dede:field.duration/}</span>
<span class="start-city">出发地: {dede:field.start_city/}</span>
</div>
<div class="gallery">
{dede:field name='body' runphp='yes'}
$body = @me;
// 使用正则表达式提取所有图片
preg_match_all('/<img.*?src="(.*?)".*?>/is', $body, $img_array);
@me = '';
if($img_array){
foreach($img_array[1] as $img){
@me .= "<img src='{$img}' alt='' />";
}
}
{/dede:field}
</div>
<div class="itinerary">
<h2>行程安排</h2>
{dede:field name='itinerary'/}
</div>
<div class="fee-info">
<div class="fee-include">
<h2>费用包含</h2>
{dede:field name='fee_include'/}
</div>
<div class="fee-exclude">
<h2>费用不包含</h2>
{dede:field name='fee_exclude'/}
</div>
</div>
<div class="booking-area">
<h2>在线预订</h2>
<form action="/plus/diy.php" method="post">
<input type="hidden" name="action" value="post" />
<input type="hidden" name="diyid" value="1" /> <!-- 这里填写你的预订表单的diyid -->
<input type="hidden" name="do" value="2" />
<!-- 从配置中读取表单字段 -->
{dede:field name='book_form' runphp='yes'}
$config = @me; // 假设@me是JSON字符串
$fields = json_decode($config, true);
if($fields && is_array($fields)){
foreach($fields as $field){
echo "<div class='form-item'>";
echo "<label>{$field['label']}:</label>";
if($field['type'] == 'text'){
echo "<input type='text' name='{$field['name']}' required />";
}elseif($field['type'] == 'tel'){
echo "<input type='tel' name='{$field['name']}' required />";
}
// 可以扩展更多类型
echo "</div>";
}
}
{/dede:field}
<input type="hidden" name="dede_fields" value='姓名,text;电话,text;人数,text;意向产品,text' /> // 这里的字段名必须和上面的一致
<input type="hidden" name="dede_fieldshash" value='<?php echo md5('姓名文本框电话文本框人数文本框意向产品文本框 dede_fields'); ?>' />
<button type="submit" class="btn-submit">提交预订</button>
</form>
</div>
</div>
</div>
{dede:include filename="footer.htm"/}
自定义表单开发 (用于预订)
这是收集用户信息的关键。
a. 创建表单:
- 后台 -> 核心 -> 自定义表单。
- 点击“增加新表单”,填写表单名称(如“线路预订”)。
- 在“表单字段列表”中,添加你需要的字段:
- 字段名:
name, 字段类型:单行文本, 提示文字:您的姓名 - 字段名:
tel, 字段类型:单行文本, 提示文字:联系电话 - 字段名:
people_num, 字段类型:单行文本, 提示文字:出行人数 - 字段名:
product_name, 字段类型:单行文本, 提示文字:意向产品(可以设置为必填)
- 字段名:
- 保存,此时会得到一个
diyid(例如1)。 - 重要: 在表单管理页面,点击你刚创建的表单,进入“管理表单字段”页面,找到最下面的 “增加HTML代码”。
- 在里面粘贴一个提交按钮的HTML代码,
<div style="text-align:center;"><input type="submit" name="submit" value="提 交" class="btn" style="width:100px;" /></div>
- 生成表单代码,并复制模板代码,创建一个新的模板文件(如
templets/default/booking.htm),把代码粘贴进去。
b. 在详情页调用表单:
使用 {dede:include file='booking.htm'/} 或使用 {dede:diyform name='表单名称'/} 标签将表单嵌入到你的详情页中。
第三部分:高级与优化
SEO优化
- URL优化: 后台 -> 系统 -> 站点参数 -> 修改“文件命名规则”,使用更友好的URL,如
{typedir}/{aid}.html。 - 标题/关键词/描述: 在发布每条内容时,务必填写“SEO标题”、“关键词”、“描述”,可以在模板中使用
{dede:field.seotitle/}等标签。 - 地图生成: 定期使用Dede自带的“更新HTML”和“生成Google SiteMap”功能。
前端美化
- 使用 Bootstrap、Element UI 等前端框架可以极大提升开发效率和页面美观度。
- 使用 jQuery 或 Vue.js 来实现更复杂的交互,如图片轮播、AJAX筛选、动态表单等。
安全性
- 权限控制: 确保后台管理权限分配清晰,避免使用过于简单的密码。
- 代码过滤: 对用户输入的内容(评论、表单等)进行过滤,防止XSS攻击,Dede默认有部分过滤,但可以进一步加强。
- 及时更新: 关注Dede官方或社区的安全公告,及时打补丁。
扩展功能
- 会员系统: 利用Dede自带的会员模块,实现用户注册、登录、积分、等级等功能。
- 支付接口: 对接支付宝、微信支付等,实现线上支付功能,这通常需要专业的开发人员介入。
- API接口: 如果需要开发小程序或App,可以为你的Dede站点开发一套API接口,返回JSON数据。
DedeCMS二次开发旅游网站,关键在于 “规划 -> 数据库 -> 模型 -> 模板 -> 逻辑” 这条主线。
- 规划先行: 明确你需要哪些功能和页面。
- 数据库是基石: 设计好自定义表,这是存储非标准内容的核心。
- 模型是桥梁: 将数据库表与Dede的内容管理系统连接起来。
- 模板是表现: 使用Dede标签和HTML/CSS/JS将数据渲染成美观的页面。
- 逻辑是灵魂: 通过修改PHP文件(如
list.php,article_archives.php)来实现复杂的业务逻辑,如筛选、表单处理等。
希望这份详细的指南能帮助你顺利完成Dede旅游网站的二次开发!如果在具体实现中遇到问题,可以随时提出。
