当前位置: 首页 > news >正文

政务咨询投诉举报网站建设湖北神润建设工程网站

政务咨询投诉举报网站建设,湖北神润建设工程网站,成都网站建设是什么意思,yum安装wordpress提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 基于node vue的电商系统 mongodb express框架前言技术栈基本功能普通用户管理员一、运行截图#xff1f;二、使用步骤1.前端main.js2.后端admin路由前言 技术栈 本项目采用… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 基于node vue的电商系统 mongodb express框架前言技术栈基本功能普通用户管理员一、运行截图二、使用步骤1.前端main.js2.后端admin路由前言 技术栈 本项目采用前后端分离的开发方式使用的技术栈是:VueNodeMongoDB前端用vue-cli搭建使用vue全家桶element-ui后端express框架数据库mongodb 基本功能 普通用户 注册、登录根据关键词对商品模糊搜索根据分类查询商品商品详情展示加入购物车及创建订单商品评论用户个人中心修改个人信息及查看订单 管理员 登录用户管理权限管理商品管理订单管理数据统计 提示以下是本篇文章正文内容下面案例可供参考 一、运行截图 二、使用步骤 1.前端main.js 代码如下示例 import Vue from vue import App from ./App import router from ./router import store from ./storeVue.config.productionTip false//图片懒加载 import LazyLoad from vue-lazyload Vue.use(LazyLoad, {error:require(./assets/img/error.png),// 占位图loading:require(./assets/img/loading.png) })//引入ElementUI库 import ElementUI from element-ui import element-ui/lib/theme-chalk/index.css Vue.use(ElementUI);//省市区联动 import VueAreaLinkage from vue-area-linkage; import vue-area-linkage/dist/index.css; Vue.use(VueAreaLinkage);//引入图标库 import assets/fonts/iconfont.css//引入全局样式 import assets/css/base.css//事件总线 Vue.prototype.$bus new Vue();new Vue({router,store,render: h h(App) }).$mount(#app)//通过methods里的代码跳转路由需要写下面代码: (不然重复点击会报错) import Router from vue-router const routerPush Router.prototype.replace Router.prototype.replace function replace(location) {return routerPush.call(this, location).catch(error error) } 2.后端admin路由 代码如下示例 import express from express import mongoose from mongoose import path from path import md5 from blueimp-md5 import formidable from formidable import config from ../src/config.js import {Administrator,User,Category,Goods,Comment,Order } from ../db/db const router express.Router();const S_KEY leavehaofoxmail.com //盐//管理员登录 router.post(/login, async (req, res) {let adminName req.body.adminName;let adminPsw md5(md5(req.body.adminPsw) S_KEY);let result await Administrator.findOne({adminName})if (result) {if (adminPsw result.password) {req.session.admin adminName;res.json({status_code: 200,message: 登录成功,})} else {res.json({status_code: 400,message: 密码错误})}} else {res.json({status_code: 400,message: 用户名不存在})} })//设置后台访问权限 router.use((req, res, next) {if (!req.session.admin) {res.json({status_code: 400,message: 无权访问})}next(); })// 验证登录状态,若未被中间件拦截则为登录状态 router.get(/isadmin, async (req, res) {console.log(req.session.admin)if(req.session.admin){let result await Administrator.findOne({adminName: req.session.admin})console.log(result)res.json({status_code: 200,message: 进入管理员界面,adminName: req.session.admin,role: result.role})}})//退出登录 router.get(/logout, (req, res) {req.session.admin ;res.json({status_code: 200,message: 已退出登录}) })/**************************************** 用户管理 *******************************************///获取用户列表 router.get(/userlist, async (req, res) {let result;if (req.query.userName) {result await User.find({userName: {$regex: req.query.userName,$options: gi}});} else {result await User.find({});}res.json({status_code: 200,message: 获取用户列表成功,total: result.length,users: result}) })//添加用户 router.post(/adduser, (req, res) {const form new formidable.IncomingForm();form.uploadDir config.uploadsAvatarPath; // 上传图片放置的文件夹form.keepExtensions true; // 保持文件的原始扩展名form.parse(req, (err, fields, files) {let avatar;if (fields.userSex 男) {avatar http://localhost: config.port /boy_avatar.svg} else {avatar http://localhost: config.port /girl_avatar.svg}if (files.userAvatar) {avatar http://localhost: config.port /avatar_uploads/ path.basename(files.userAvatar.path);}let userInfo {userName: fields.userName,password: md5(md5(fields.userPsw) S_KEY), //加密密码userEmail: fields.userEmail,userPhone: fields.userPhone,userSex: fields.userSex,userSign: fields.userSign,userAdress: fields.userAdress,nickName: fields.nickName,// userAdress:fields.userAdress.replace(/,/g,),userAvatar: avatar}User.create(userInfo, (err, doc) {console.log(err, doc)if (!err) {res.json({status_code: 200,message: 添加用户成功,})} else {res.json({status_code: 400,message: 内部错误,添加用户失败,})}})}) })//编辑用户 router.post(/edituser, (req, res) {const form new formidable.IncomingForm();form.uploadDir config.uploadsAvatarPath; // 上传图片放置的文件夹form.keepExtensions true; // 保持文件的原始扩展名form.parse(req, (err, fields, files) {let avatar;let userInfo {userName: fields.userName,userEmail: fields.userEmail,userPhone: fields.userPhone,userSex: fields.userSex,userSign: fields.userSign,userAdress: fields.userAdress,nickName: fields.nickName}if (files.userAvatar) {avatar http://localhost: config.port /avatar_uploads/ path.basename(files.userAvatar.path);userInfo.userAvatar avatar}if (fields.userPsw) {userInfo.password md5(md5(fields.userPsw) S_KEY); //加密密码}User.updateOne({userName: fields.userName}, userInfo).then((doc) {res.json({status_code: 200,message: 修改用户成功,})}).catch((err) {res.json({status_code: 400,message: 内部错误,修改用户信息失败,})})}) })//删除用户 router.get(/deleteuser, (req, res) {let userName req.query.userName;User.findOneAndDelete({userName}).then((doc) {res.json({status_code: 200,message: 删除用户成功,})}).catch((err) {res.json({status_code: 400,message: 内部错误,删除用户失败,})}) })/**************************************** 权限管理 *******************************************///获取管理员列表 router.get(/adminlist, async (req, res) {let result;if (req.query.adminName) {result await Administrator.find({adminName: {$regex: req.query.adminName,$options: gi}});} else {result await Administrator.find({});}res.json({status_code: 200,message: 获取管理员列表成功,total: result.length,administrators: result}) })//添加管理员 router.post(/addadmin, (req, res) {let regFrom req.body;console.log(regFrom)let adminInfo {adminName: regFrom.adminName,password: md5(md5(regFrom.adminPsw) S_KEY), //加密密码role: regFrom.adminRole}Administrator.create(adminInfo, (err, doc) {console.log(err, doc)if (!err) {res.json({status_code: 200,message: 添加管理员成功,})} else {res.json({status_code: 400,message: 内部错误,添加管理员失败,})}}) })//检查管理员名是否已注册 router.get(/checkname, async (req, res) {let adminName req.query.adminName;let isNameReg await Administrator.findOne({adminName})if (isNameReg) {res.json({status_code: 400,message: 该名称已注册})} else {res.json({status_code: 200,message: 该名称可以使用})} })//编辑管理员 router.post(/editadmin, async (req, res) {let regFrom req.body;console.log(regFrom);let adminInfo {adminName: regFrom.adminName,role: regFrom.adminRole}if (regFrom.adminPsw) {adminInfo.password md5(md5(regFrom.adminPsw) S_KEY); //加密密码}Administrator.updateOne({adminName: regFrom.adminName}, adminInfo).then((doc) {res.json({status_code: 200,message: 修改管理员信息成功,})}).catch((err) {res.json({status_code: 400,message: 内部错误,修改管理员信息失败,})}) })//删除管理员 router.get(/deleteadmin, (req, res) {let adminName req.query.adminName;Administrator.findOneAndDelete({adminName}).then((doc) {res.json({status_code: 200,message: 删除管理员成功,})}).catch((err) {res.json({status_code: 400,message: 内部错误,删除管理员失败,})}) })/**************************************** 商品管理 *******************************************///获取分类列表 router.get(/catelist, async (req, res) {let result;if (req.query.cateId) {result await Category.find({cateId: req.query.cateId}).sort(cateId);} else {result await Category.find({}).sort(cateId);}res.json({status_code: 200,message: 获取分类列表成功,total: result.length,categories: result}) })//检查分类ID是否已存在 router.get(/checkcateid, async (req, res) {let cateId req.query.cateId;let isIdReg await Category.findOne({cateId})if (isIdReg) {res.json({status_code: 400,message: 此ID已被使用})} else {res.json({status_code: 200,message: 此ID可以使用})} })//检查分类名称是否已存在 router.get(/checkcatename, async (req, res) {let cateName req.query.cateName;let isIdReg await Category.findOne({cateName})if (isIdReg) {res.json({status_code: 400,message: 此名称已被使用})} else {res.json({status_code: 200,message: 此名称可以使用})} })//添加分类 router.post(/addcate, (req, res) {let regFrom req.body;console.log(regFrom)let cateInfo {cateId: regFrom.cateId,cateName: regFrom.cateName,cateCounts: 0,cateSales: 0}Category.create(cateInfo, (err, doc) {console.log(err, doc)if (!err) {res.json({status_code: 200,message: 添加分类成功,})} else {res.json({status_code: 400,message: 内部错误,添加分类失败,})}}) })//编辑分类 router.post(/editcate, async (req, res) {let editFrom req.body;Category.updateOne({cateId: editFrom.cateId}, editFrom).then((doc) {res.json({status_code: 200,message: 修改分类信息成功,})}).catch((err) {res.json({status_code: 400,message: 内部错误,修改分类信息失败,})}) })//删除分类 router.get(/deletecate, (req, res) {let cateId req.query.cateId;Category.findOneAndDelete({cateId}).then(async (doc) {//删除商品下评论let result await Goods.find({goodsCategory: cateId})console.log(result, result)for (let i 0; i result.length; i) {await Comment.deleteMany({goodsId: result[i].goodsId})}//删除分类下所有商品await Goods.deleteMany({goodsCategory: cateId})res.json({status_code: 200,message: 删除分类成功,})}).catch((err) {res.json({status_code: 400,message: 内部错误,删除分类失败,})}) })//获取商品列表 router.get(/goodslist, async (req, res) {let result;if (req.query.goodsCategory) {if (req.query.goodsId) {let resultId await Goods.find({goodsId: req.query.goodsId,goodsCategory: req.query.goodsCategory}).sort(goodsCategory);let resultName await Goods.find({goodsName: {$regex: req.query.goodsId,$options: gi},goodsCategory: req.query.goodsCategory}).sort(goodsCategory);if (resultId.length ! 0) {result resultId} else {result resultName}} else {result await Goods.find({goodsCategory: req.query.goodsCategory}).sort(goodsCategory);}} else {if (req.query.goodsId) {let resultId await Goods.find({goodsId: req.query.goodsId}).sort(goodsCategory);let resultName await Goods.find({goodsName: {$regex: req.query.goodsId,$options: gi}}).sort(goodsCategory);if (resultId.length ! 0) {result resultId} else {result resultName}} else {result await Goods.find({}).sort(goodsCategory);}}res.json({status_code: 200,message: 获取分类列表成功,total: result.length,goods: result}) })//获取商品的分类 router.get(/goodscate, async (req, res) {let result await Category.findOne({cateId: req.query.cateId});res.json({status_code: 200,message: 获取分类信息成功,goodsCate: result.cateName}) })//检查商品ID是否已存在 router.get(/checkgoodsid, async (req, res) {let goodsId req.query.goodsId;let isIdReg await Goods.findOne({goodsId})console.log(isIdReg)if (isIdReg) {res.json({status_code: 400,message: 此ID已被使用})} else {res.json({status_code: 200,message: 此ID可以使用})} })//添加商品 router.post(/addgoods, (req, res) {const form new formidable.IncomingForm();form.uploadDir config.uploadsGoodsPath; // 上传图片放置的文件夹form.keepExtensions true; // 保持文件的原始扩展名form.parse(req, (err, fields, files) {let goodsInfo {goodsId: fields.goodsId,shortName: fields.shortName,goodsName: fields.goodsName,goodsPrice: fields.goodsPrice,normalPrice: fields.normalPrice,salesTips: fields.salesTips,goodsCategory: fields.goodsCategory,goodsCounts: Number(fields.goodsCounts),goodsImg: http://localhost: config.port /uploads/ path.basename(files.goodsImg.path),goodsComments: 0}Goods.create(goodsInfo, async (err, doc) {//更新商品分类里的商品数量let result await Goods.find({goodsCategory: fields.goodsCategory});Category.updateOne({cateId: fields.goodsCategory}, {cateCounts: result.length}).then(doc console.log(doc, doc)).catch(err console.log(err, err))if (!err) {res.json({status_code: 200,message: 添加商品成功,})} else {res.json({status_code: 400,message: 内部错误,添加商品失败,})}})}) })//编辑商品 router.post(/editgoods, (req, res) {const form new formidable.IncomingForm();form.uploadDir config.uploadsGoodsPath; // 上传图片放置的文件夹form.keepExtensions true; // 保持文件的原始扩展名form.parse(req, (err, fields, files) {console.log(fields, files)let goodsInfo {goodsId: fields.goodsId,shortName: fields.shortName,goodsName: fields.goodsName,goodsPrice: fields.goodsPrice,normalPrice: fields.normalPrice,salesTips: fields.salesTips,goodsCategory: fields.goodsCategory,goodsCounts: Number(fields.goodsCounts),}if (files.goodsImg) {goodsInfo.userAvatar http://localhost: config.port /uploads/ path.basename(files.goodsImg.path);}Goods.updateOne({goodsId: fields.goodsId}, goodsInfo).then(async (doc) {//更新编辑前商品分类里的商品数量let resultOld await Goods.find({goodsCategory: fields.goodsOldCate});Category.updateOne({cateId: fields.goodsOldCate}, {cateCounts: resultOld.length}).then(doc console.log(doc, doc)).catch(err console.log(err, err));//更新编辑后商品分类里的商品数量let result await Goods.find({goodsCategory: fields.goodsCategory});Category.updateOne({cateId: fields.goodsCategory}, {cateCounts: result.length}).then(doc console.log(doc, doc)).catch(err console.log(err, err));res.json({status_code: 200,message: 修改商品成功,})}).catch((err) {console.log(err)res.json({status_code: 400,message: 内部错误,修改商品信息失败,})})}) })//删除商品 router.get(/deletegoods, (req, res) {let goodsId req.query.goodsId;let goodsCategory req.query.goodsCategory;Goods.findOneAndDelete({goodsId}).then(async (doc) {//删除该商品下所有评论Comment.deleteMany({goodsId}).then(doc console.log(doc))//更新删除后商品分类里的商品数量let result await Goods.find({goodsCategory});Category.updateOne({cateId: goodsCategory}, {cateCounts: result.length}).then(doc console.log(doc, doc)).catch(err console.log(err, err));res.json({status_code: 200,message: 删除商品成功,})}).catch((err) {res.json({status_code: 400,message: 内部错误,删除商品失败,})}) })/**************************************** 订单管理 *******************************************///获取订单列表 router.get(/orderlist, async (req, res) {let result;if (req.query.userName) {let resultId [];if (req.query.userName.length 24) {resultId await Order.find({_id: mongoose.Types.ObjectId(req.query.userName)}).sort(-orderTime);}let resultName await Order.find({userName: {$regex: req.query.userName,$options: gi}}).sort(-orderTime);if (resultId.length ! 0) {result resultId} else {result resultName}} else {result await Order.find({}).sort(-orderTime);}res.json({status_code: 200,message: 获取订单列表成功,total: result.length,orders: result}) })//编辑订单信息 router.post(/editorder, async (req, res) {let editFrom req.body;console.log(editFrom);Order.updateOne({_id: mongoose.Types.ObjectId(editFrom._id)}, editFrom).then((doc) {res.json({status_code: 200,message: 修改订单信息成功,})}).catch((err) {console.log(err)res.json({status_code: 400,message: 内部错误,修改订单信息失败,})}) })//删除订单 router.get(/deleteorder, (req, res) {Order.findOneAndDelete({_id: mongoose.Types.ObjectId(req.query._id)}).then((doc) {res.json({status_code: 200,message: 删除订单成功,})}).catch((err) {res.json({status_code: 400,message: 内部错误,删除订单失败,})}) })/**************************************** 数据统计 *******************************************///获取数据统计数据 router.get(/datalist, async (req, res) {let result await Category.find({}).sort(cateId);let xAxisData [];let seriesData [];for (let i 0; i result.length; i) {xAxisData.push(result[i].cateName);seriesData.push(result[i].cateSales);}let option {title: {text: 各分类月销量},tooltip: {},legend: {data: [销量]},xAxis: {data: xAxisData},yAxis: {},series: [{name: 销量,type: bar,data: seriesData}]};console.log(xAxisData,seriesData,option)res.json({status_code: 200,message: 获取数据统计信息成功,option: option}) })export default router;---# 源码 https://pan.baidu.com/s/1ADfDdHbOYui8vwOTzwCbUA?pwd8767
文章转载自:
http://www.morning.nnpfz.cn.gov.cn.nnpfz.cn
http://www.morning.yhrfg.cn.gov.cn.yhrfg.cn
http://www.morning.ydhmt.cn.gov.cn.ydhmt.cn
http://www.morning.tdmgs.cn.gov.cn.tdmgs.cn
http://www.morning.rkxk.cn.gov.cn.rkxk.cn
http://www.morning.wlqbr.cn.gov.cn.wlqbr.cn
http://www.morning.mrskk.cn.gov.cn.mrskk.cn
http://www.morning.qdxkn.cn.gov.cn.qdxkn.cn
http://www.morning.plqsc.cn.gov.cn.plqsc.cn
http://www.morning.bby45.cn.gov.cn.bby45.cn
http://www.morning.lxfdh.cn.gov.cn.lxfdh.cn
http://www.morning.yrjhr.cn.gov.cn.yrjhr.cn
http://www.morning.pyncm.cn.gov.cn.pyncm.cn
http://www.morning.qyhcg.cn.gov.cn.qyhcg.cn
http://www.morning.tgtrk.cn.gov.cn.tgtrk.cn
http://www.morning.jfbrt.cn.gov.cn.jfbrt.cn
http://www.morning.darwallet.cn.gov.cn.darwallet.cn
http://www.morning.gqwbl.cn.gov.cn.gqwbl.cn
http://www.morning.rydbs.cn.gov.cn.rydbs.cn
http://www.morning.lstmg.cn.gov.cn.lstmg.cn
http://www.morning.wmcng.cn.gov.cn.wmcng.cn
http://www.morning.wdpt.cn.gov.cn.wdpt.cn
http://www.morning.tpxgm.cn.gov.cn.tpxgm.cn
http://www.morning.qjfkz.cn.gov.cn.qjfkz.cn
http://www.morning.ykwbx.cn.gov.cn.ykwbx.cn
http://www.morning.zwgrf.cn.gov.cn.zwgrf.cn
http://www.morning.pxbrg.cn.gov.cn.pxbrg.cn
http://www.morning.ktmbp.cn.gov.cn.ktmbp.cn
http://www.morning.lrylj.cn.gov.cn.lrylj.cn
http://www.morning.fhcwm.cn.gov.cn.fhcwm.cn
http://www.morning.pgrsf.cn.gov.cn.pgrsf.cn
http://www.morning.sxfmg.cn.gov.cn.sxfmg.cn
http://www.morning.mbdbe.cn.gov.cn.mbdbe.cn
http://www.morning.xtkw.cn.gov.cn.xtkw.cn
http://www.morning.chxsn.cn.gov.cn.chxsn.cn
http://www.morning.pmysp.cn.gov.cn.pmysp.cn
http://www.morning.mnsts.cn.gov.cn.mnsts.cn
http://www.morning.qmsbr.cn.gov.cn.qmsbr.cn
http://www.morning.wjlnz.cn.gov.cn.wjlnz.cn
http://www.morning.zqkr.cn.gov.cn.zqkr.cn
http://www.morning.lwtfr.cn.gov.cn.lwtfr.cn
http://www.morning.yfcbf.cn.gov.cn.yfcbf.cn
http://www.morning.plqqn.cn.gov.cn.plqqn.cn
http://www.morning.qbfqb.cn.gov.cn.qbfqb.cn
http://www.morning.mrfgy.cn.gov.cn.mrfgy.cn
http://www.morning.ygth.cn.gov.cn.ygth.cn
http://www.morning.yhjrc.cn.gov.cn.yhjrc.cn
http://www.morning.sjwqr.cn.gov.cn.sjwqr.cn
http://www.morning.ghphp.cn.gov.cn.ghphp.cn
http://www.morning.fmswb.cn.gov.cn.fmswb.cn
http://www.morning.lwnwl.cn.gov.cn.lwnwl.cn
http://www.morning.mkbc.cn.gov.cn.mkbc.cn
http://www.morning.tngdn.cn.gov.cn.tngdn.cn
http://www.morning.ddqdl.cn.gov.cn.ddqdl.cn
http://www.morning.kfmnf.cn.gov.cn.kfmnf.cn
http://www.morning.bmqls.cn.gov.cn.bmqls.cn
http://www.morning.sjbty.cn.gov.cn.sjbty.cn
http://www.morning.fhqdb.cn.gov.cn.fhqdb.cn
http://www.morning.sgnxl.cn.gov.cn.sgnxl.cn
http://www.morning.ntqqm.cn.gov.cn.ntqqm.cn
http://www.morning.mmjyk.cn.gov.cn.mmjyk.cn
http://www.morning.hmmtx.cn.gov.cn.hmmtx.cn
http://www.morning.rhsg.cn.gov.cn.rhsg.cn
http://www.morning.qpxrr.cn.gov.cn.qpxrr.cn
http://www.morning.dfrenti.com.gov.cn.dfrenti.com
http://www.morning.fthcn.cn.gov.cn.fthcn.cn
http://www.morning.tmnyj.cn.gov.cn.tmnyj.cn
http://www.morning.tsrg.cn.gov.cn.tsrg.cn
http://www.morning.uytae.cn.gov.cn.uytae.cn
http://www.morning.ahlart.com.gov.cn.ahlart.com
http://www.morning.jybj.cn.gov.cn.jybj.cn
http://www.morning.pylpd.cn.gov.cn.pylpd.cn
http://www.morning.krjrb.cn.gov.cn.krjrb.cn
http://www.morning.sbwr.cn.gov.cn.sbwr.cn
http://www.morning.qbpqw.cn.gov.cn.qbpqw.cn
http://www.morning.kscwt.cn.gov.cn.kscwt.cn
http://www.morning.wtyqs.cn.gov.cn.wtyqs.cn
http://www.morning.tdnbw.cn.gov.cn.tdnbw.cn
http://www.morning.kfmlf.cn.gov.cn.kfmlf.cn
http://www.morning.drmbh.cn.gov.cn.drmbh.cn
http://www.tj-hxxt.cn/news/261491.html

相关文章:

  • 去哪学做网站企查查在线查询网页版
  • dedecms搭建购物网站ie浏览器网页版
  • 小学网站模板源码广西搜索推广
  • 金华做公司网站中国正规的加盟网站
  • 郓城网站建设价格企业网站建设公司 末路
  • 2017建站做网站前台用什么问题
  • 有人利用婚恋网站做微商廊坊网站开发公司
  • 青岛本地招聘网站硬件开发语言
  • 聊城做网站的公司流程wordpress添加媒体无反应
  • 网页设计网站视频南昌做网站价格
  • 太原seo网站优化桂林象鼻山景区简介
  • 做运动鞋评价的网站企业注册名称查询
  • 做网站什么硬盘好如何进行搜索引擎的优化
  • 杭州亚太建设监理咨询有限公司中标网站企业网站案例建设要求
  • 制作网站账号系统下载宝硬盘做网站
  • 大学英文网站建设举措百度搜索引擎的网址
  • 邹城手机网站建设做电商与做网站的区别
  • 软装设计师是干什么的网站为什么做优化ppt
  • 什么网站好重庆最新数据消息
  • 宜城做网站wordpress 域名访问还是临时域名
  • 网站链接云数据库咸阳学校网站建设公司
  • 网站图片快速加载微信小程序是什么模式
  • php网站留言板模板下载排名前十的网站
  • 宁波企业免费建站网络管理系统软件有哪些
  • 网站建设技术百科网站建设服务多少钱
  • 如何制作网站导航栏移动互联网开发实验报告
  • 大型自适应的网站开发网站开发预留接口
  • 动态模板网站建设怎么自己弄网站
  • 天津网站建设 企航互联中国建设网上银行个人登录
  • 电商旅游网站策划书竞价外包