Commit 4e1c48c8 authored by 任国军's avatar 任国军

add class & fix header

parent 9880cadd
Pipeline #21628 passed with stage
in 47 seconds
......@@ -3,213 +3,26 @@
const Controller = require('egg').Controller;
class InstitutionController extends Controller {
// 机构列表
async getInstitutions() {
const { ctx } = this;
const inputParams = ctx.request.query;
const ret = await ctx.service.course.v4.institution.getInstitutions(inputParams);
ctx.success(ret);
}
// 机构详情
async getInstitution() {
const { ctx } = this;
let inputParams = ctx.params;
const query = ctx.query;
inputParams = Object.assign(inputParams, query);
const result = await ctx.service.course.v4.institution.getInstitution(inputParams);
ctx.success({ result });
}
// 课程列表
async getClasses() {
async getClassList() {
const { ctx } = this;
const inputParams = ctx.request.query;
const ret = await ctx.service.course.v4.institution.getClasses(inputParams);
const queryParams = ctx.request.query;
const ret = await ctx.service.course.v4.institution.getClassList(queryParams);
ctx.success(ret);
}
// 课程详情
async getClass() {
async getClassInfo() {
const { ctx } = this;
const class_id = ctx.params.class_id;
if (!class_id) {
ctx.failed('error class_id');
}
const inputParams = ctx.request.query;
inputParams.id = class_id;
const ret = await ctx.service.course.v4.institution.getClass(inputParams);
ctx.success(ret);
}
// 老师列表
async getTeachers() {
const { ctx } = this;
const inputParams = ctx.request.query;
if (ctx.isEmpty(inputParams.institution_id)) {
ctx.failed('institution_id is empty');
}
const ret = await ctx.service.course.v4.institution.getTeachers(inputParams);
ctx.success(ret);
}
// 老师详情
async getTeacher() {
const { ctx } = this;
const teacher_id = ctx.params.teacher_id;
if (!teacher_id) {
ctx.failed('error teacher_id');
}
const ret = await ctx.service.course.v4.institution.getTeacher(teacher_id);
ctx.success(ret);
}
// 获取分类
async getCats() {
const { ctx } = this;
const ret = await ctx.service.course.v4.institution.getCats();
ctx.success(ret);
}
// 搜索
async search() {
const { ctx } = this;
const inputParams = ctx.request.query;
const ret = await ctx.service.course.v4.institution.search(inputParams);
ctx.success(ret);
}
// 用户搜索历史
async getUserSearch() {
const { ctx, service } = this;
const ret = await service.course.v4.institution.getUserSearch();
ctx.success(ret);
}
// 获取热搜
async getHotSearch() {
const { ctx, service } = this;
const ret = await service.course.v4.institution.getHotSearch();
ctx.success(ret);
}
// 删除用户搜索历史
async deleteUserSearch() {
const { ctx, service } = this;
await service.course.v4.institution.deleteUserSearch();
ctx.success();
}
// 评论列表
async getComments() {
const { ctx, service } = this;
const inputParams = ctx.request.query;
const ret = await service.course.v4.institution.getComments(inputParams);
ctx.success(ret);
}
// 搜索联想
async getSuggestSearch() {
const { ctx, service } = this;
const inputParams = ctx.request.query;
const ret = await service.course.v4.institution.getSuggestSearch(inputParams);
ctx.success(ret);
}
// 用户收藏机构列表
async getUserCollectedInstitutions() {
const { ctx, service } = this;
const inputParams = ctx.request.query;
const ret = await service.course.v4.institution.getUserCollectedInstitutions(inputParams);
ctx.success(ret);
}
// 用户收藏课程列表
async getUserCollectedClasses() {
const { ctx, service } = this;
const inputParams = ctx.request.query;
const ret = await service.course.v4.institution.getUserCollectedClasses(inputParams);
ctx.success(ret);
}
// 根据分类获取选课指南
async getArticlesByCat() {
const { ctx, service } = this;
const inputParams = ctx.request.query;
if (ctx.isEmpty(inputParams) || ctx.isEmpty(inputParams.cat_id)) {
ctx.failed('cat_id is empty');
}
const ret = await service.course.v4.institution.getArticlesByCat(inputParams);
ctx.success(ret);
}
// 获取选课指南详情
async getArticle() {
const { ctx, service } = this;
const inputParams = ctx.params;
if (ctx.isEmpty(inputParams) || ctx.isEmpty(inputParams.id)) {
ctx.failed('article_id is empty');
}
const ret = await service.course.v4.institution.getArticle(Number(inputParams.id));
ctx.success(ret);
}
// 点赞
async like() {
const { ctx, service } = this;
const inputParams = ctx.request.body;
if (ctx.isEmpty(inputParams) || ctx.isEmpty(inputParams.type) || ctx.isEmpty(inputParams.type_id)) {
ctx.failed('参数错误');
}
const ret = await service.course.v4.institution.like(inputParams);
ctx.success(ret);
}
// 取消点赞
async unlike() {
const { ctx, service } = this;
const inputParams = ctx.request.body;
if (ctx.isEmpty(inputParams) || ctx.isEmpty(inputParams.type) || ctx.isEmpty(inputParams.type_id)) {
ctx.failed('参数错误');
}
const ret = await service.course.v4.institution.unlike(inputParams);
ctx.success(ret);
}
// 获取推荐选课指南
async getArticlesByRecommend() {
const { ctx, service } = this;
const inputParams = ctx.request.query;
const ret = await ctx.service.course.v4.institution.getClassInfo(class_id);
const ret = await service.course.v4.institution.getArticlesByRecommend(inputParams);
ctx.success(ret);
}
}
......
......@@ -10,22 +10,30 @@ class OptionController extends Controller {
async getOptions() {
const { ctx } = this;
const results = await ctx.service.course.v4.option.getOptions();
const results = await ctx.service.course.v5.option.getOptions();
ctx.success({ results });
}
async getBanners() {
async getBannerList() {
const { ctx, service } = this;
const inputParams = ctx.request.query;
if (ctx.isEmpty(inputParams.alias)) {
const queryParams = ctx.request.query;
if (ctx.isEmpty(queryParams.alias)) {
ctx.failed('alias is empty');
}
const ret = await service.course.v4.option.getBanners(inputParams.alias);
const ret = await service.course.v5.option.getBannerList(queryParams.alias);
ctx.success(ret);
}
// 获取分类列表
async getCategoryList() {
const { ctx, service } = this;
const queryParams = ctx.request.query;
const ret = await service.course.v5.option.getCategoryList(queryParams);
ctx.success(ret);
}
}
module.exports = OptionController;
......@@ -17,7 +17,7 @@ module.exports = (options, app) => {
}
const openid = userInfo.openid;
const phone = userInfo.phone;
const authToken = ctx.headers.auth_token;
const authToken = ctx.headers.authorization;
if (ctx.helper.md5(uuid + openid + phone + 'jbwl') !== authToken) {
ctx.failed('login auth error');
}
......
......@@ -4,7 +4,7 @@
const moment = require('moment');
module.exports = app => {
const { STRING, INTEGER, DATE, ENUM } = app.Sequelize;
const { STRING, INTEGER, DATE } = app.Sequelize;
const CourseBanner = app.classModel.define('course_banner', {
id: {
......@@ -17,7 +17,7 @@ module.exports = app => {
url: STRING,
link: STRING,
sort: INTEGER,
status: ENUM('offline', 'online'),
status: INTEGER,
is_deleted: INTEGER,
created_time: {
type: DATE,
......
......@@ -4,7 +4,7 @@
const moment = require('moment');
module.exports = app => {
const { STRING, INTEGER, DATE, ENUM } = app.Sequelize;
const { STRING, INTEGER, DATE } = app.Sequelize;
const CourseBannerType = app.classModel.define('course_banner_type', {
id: {
......@@ -14,7 +14,7 @@ module.exports = app => {
},
title: STRING,
alias: STRING,
status: ENUM('offline', 'online'),
status: INTEGER,
is_deleted: INTEGER,
created_time: {
type: DATE,
......
......@@ -17,7 +17,6 @@ module.exports = app => {
name: STRING,
selected_icon: STRING,
unselected_icon: STRING,
color: STRING,
status: INTEGER,
is_deleted: INTEGER,
sort: INTEGER,
......
......@@ -9,4 +9,11 @@ module.exports = app => {
router.post('third', '/login/wechat', 'course.v5.user.loginByWX');// 微信登录
router.post('third', '/user/register_user', miniAuth, 'course.v5.user.registerUserInfo');// 授权后注册用户
router.get('third', '/user/info', miniAuth, 'course.v5.user.getUserInfo');// 获取用户信息
router.get('third', '/category/all', 'course.v5.option.getCategoryList');// 获取分类列表
router.get('third', '/banner/all', 'course.v5.option.getBannerList');// 获取banner列表
router.get('third', '/class/all', 'course.v5.institution.getClassList');// 获取课程列表
router.get('third', '/class/:class_id', 'course.v5.institution.getClassInfo');// 获取课程详情
};
......@@ -8,662 +8,98 @@ const moment = require('moment');
const sequelize = require('sequelize');
class InstitutionSubService extends Service {
// 获取分类
async getCats() {
const { ctx } = this;
const AllCats = await ctx.classModel.V4.CourseCat.findAll({ where: { status: 1, is_deleted: 0 } });
const rootCats = [];
let ret = [];
// 先取出一级分类
for (const v of AllCats) {
if (v.parent_id === 0) {
rootCats[v.id] = v.dataValues;
rootCats[v.id].child = [{ id: 0, value: v.id, name: '全部', parent_id: 0, image: 'http://r.51gjj.com/webpublic/images/20191118/s6yRUsc5kclyu.png', active_image: 'http://r.51gjj.com/webpublic/images/20191118/zYHkYp85vxk5m.png', color: '', tips: '', status: 'online', is_deleted: 0 }];
}
}
// 放入二级分类
for (const v of AllCats) {
if (v.parent_id > 0) {
v.value = v.id;
rootCats[v.parent_id].child.push(v);
}
}
const sort = function(a, b) {
return a.sort - b.sort;
};
// 整理
for (const v of rootCats) {
if (!ctx.isEmpty(v)) {
v.child = R.sort(sort)(v.child);
ret.push(v);
}
}
ret = R.sort(sort)(ret);
return { results: ret };
}
// 获取机构详情
async getInstitution(input) {
const { ctx } = this;
const userUuid = ctx.userUuid;
const { institution_id } = input;
const lat = ctx.isEmpty(input.lat) ? 0 : input.lat;
const lng = ctx.isEmpty(input.lng) ? 0 : input.lng;
let institution = await ctx.classModel.V4.CourseInstitution.findOne({ where: { id: institution_id, status: 'online', is_deleted: 0 } });
if (ctx.isEmpty(institution)) {
ctx.failed('机构不存在');
}
institution = institution.dataValues;
// 顶部相册
const images = await ctx.classModel.V4.CourseImages.findAll({ where: { type: 1, type_id: institution_id, status: 'online', is_deleted: 0 } });
// 去重
const checkList = [];
let album = [];
for (const v of images) {
if ((v.is_video === 0 && checkList.includes(v.image_url)) || (v.is_video === 1 && checkList.includes(v.video_url))) {
continue;
}
album.push(v);
}
// 排序,视频在前
const albumSort = function(a, b) {
if (a.is_video === b.is_video) {
return a.sort - b.sort;
}
return b.is_video - a.is_video;
};
album = R.sort(albumSort)(album);
// 学习成果
const student_video = await ctx.classModel.V4.CourseStudentVideo.findAll({ where: { institution_id, status: 'online', is_deleted: 0 }, order: [[ 'sort', 'asc' ]] });
// 教师
const teachers = await ctx.classModel.V4.CourseTeacher.findAll({ where: { institution_id, status: 'online', is_deleted: 0 }, raw: true });
// 课程
const classes = await ctx.classModel.V4.CourseClass.findAll({ where: { institution_id, status: 'online', is_deleted: 0 }, raw: true });
// 处理课程封面图
const classHandle = [];
if (classes.length > 0) {
for (const v of classes) {
classHandle.push(ctx.classModel.V4.CourseImages.findOne({ where: { type: 2, type_id: v.id, status: 'online', is_deleted: 0 }, order: [[ 'sort', 'asc' ]] }));
}
const classImages = await Promise.all(classHandle).then(result => {
return result;
}).catch(error => {
ctx.failed(error);
});
for (const i in classes) {
classes[i].image = classImages[i];
}
}
// 校区
let areas = await ctx.classModel.V4.CourseArea.findAll({ where: { institution_id, status: 'online', is_deleted: 0 }, raw: true });
const areaHandle = [];
if (areas.length > 0) {
for (const v of areas) {
areaHandle.push(this.formatArea(v, { lng, lat }));
}
areas = await Promise.all(areaHandle).then(result => {
return result;
}).catch(error => {
ctx.failed(error);
});
}
areas = _.orderBy(areas, [ 'distance' ], [ 'asc' ]);
// 是否已收藏
const userCollect = await ctx.classModel.V4.CourseUserCollection.findOne({ where: { type: 1, type_id: institution_id, user_uuid: userUuid, is_deleted: 0 } });
// 获取所有标签
const allTags = await ctx.classModel.V4.CourseTag.findAll({ where: { status: 'online', is_deleted: 0 } });
const tagList = [];
for (const v of allTags) {
tagList[v.id] = v;
}
let tags = await ctx.classModel.V4.CourseInstitutionToTag.findAll({ where: { institution_id: institution.id, status: 'online', is_deleted: 0 } });
tags = _.orderBy(tags, [ 'sort' ], [ 'asc' ]);
institution.tags = [];
for (const v of tags) {
institution.tags.push(tagList[v.tag_id]);
}
institution.phone = areas.length > 0 ? areas[0].phone : '';
institution.distance = areas.length > 0 ? String(areas[0].distance) + 'km' : '无法计算';
institution.travel_method = areas.length > 0 ? areas[0].travel_method : '';
institution.travel_tips = areas.length > 0 ? areas[0].travel_tips : '';
const ret = {
album,
detail: institution,
student_video,
teachers,
classes,
areas,
is_collected: ctx.isEmpty(userCollect) ? 0 : 1,
};
return ret;
}
// 处理校区
async formatArea(area, location) {
const { ctx, service } = this;
if (ctx.isEmpty(area)) {
return {};
}
const distance = await service.course.v4.lbs.getDistance({ lng: location.lng, lat: location.lat }, { lng: area.lng, lat: area.lat });
// 暂定3公里以内步行
area.travel_method = distance < 3000 ? 'walking' : 'driving';
const lbsResult = await service.course.v4.lbs.getLBSDistance(area.travel_method, { lng: location.lng, lat: location.lat }, [{ lng: area.lng, lat: area.lat }]);
if (lbsResult.results.length > 0) {
area.distance = parseFloat((lbsResult.results[0].distance / 1000).toFixed(1));
area.duration = lbsResult.results[0].duration;
const minute = area.travel_method === 'walking' ? Math.ceil(area.distance / 0.08) : Math.ceil(area.duration / 60);
area.travel_tips = area.travel_method === 'walking' ? `距我${area.distance}km,步行${minute}分钟` : `距我${area.distance}km,开车${minute}分钟`;
} else {
area.distance = 999999;
area.duration = 0;
area.travel_tips = '';
}
return area;
}
// 机构列表
async getInstitutions(input) {
// 课程列表
async getClassList(input) {
const { ctx } = this;
const userUuid = ctx.userUuid;
const { cat_id, age, address } = input;
const lat = ctx.isEmpty(input.lat) ? 0 : input.lat;
const lng = ctx.isEmpty(input.lng) ? 0 : input.lng;
// 保存定位记录
if (address && lat && lng) {
ctx.classModel.V4.CourseLogUserGps.create({ user_uuid: userUuid, address, lat, lng, created_time: moment().format('YYYY-MM-DD HH:mm:ss') });
}
let institutionList = [];
let institutionCats = [];
const filter = { where: { status: 'online', is_deleted: 0 } };
// 年龄筛选
if (Number(age) > 0) {
filter.where.min_age = { $lte: age };
filter.where.max_age = { $gte: age };
}
// 分类筛选
if (Number(cat_id) > 0) {
// 如果是一级分类,则需要加入该分类下所有子分类
const cats = await ctx.classModel.V4.CourseCat.findAll({ where: { parent_id: cat_id, status: 'online', is_deleted: 0 } });
const catIds = R.pluck('id', cats);
catIds.push(Number(cat_id));
institutionCats = await ctx.classModel.V4.CourseInstitutionToCat.findAll({ where: { status: 'online', is_deleted: 0, cat_id: { $in: catIds } } });
const institutionIds = R.pluck('institution_id', institutionCats);
filter.where.id = { $in: institutionIds };
}
institutionList = await ctx.classModel.V4.CourseInstitution.findAll(filter);
institutionList = R.pluck('dataValues', institutionList);
const ret = await this.formatInstitutionList(institutionList, input);
return ret;
}
// 格式化机构列表
async formatInstitutionList(institutionList, input) {
const { ctx, service } = this;
const userUuid = ctx.userUuid;
const distance = Number(input.distance) || 0;
const page = Number(input.page) || 1;
const limit = Number(input.limit) || 10;
const { lng, lat } = input;
let institutionCats = [];
let institutionIds = R.pluck('id', institutionList);
// 获取机构对应的校区
const areaList = await ctx.classModel.V4.CourseArea.findAll({ where: { status: 'online', is_deleted: 0, institution_id: { $in: institutionIds } } });
// 计算校区对应的距离
const areaHandle = [];
for (const v of areaList) {
areaHandle.push(service.course.v4.lbs.getDistance({ lat, lng }, { lat: v.lat, lng: v.lng }));
}
const areaDistanceCalcResult = await Promise.all(areaHandle).then(result => {
return result;
}).catch(error => {
ctx.failed(error);
});
for (const i in areaList) {
areaList[i].distance = areaDistanceCalcResult[i];
}
// 选出最短距离的校区
for (const v of areaList) {
for (const i in institutionList) {
if (institutionList[i].id === v.institution_id) {
if (ctx.isEmpty(institutionList[i].area) || (institutionList[i].area.distance > v.distance)) {
institutionList[i].area = v;
}
}
}
}
// 格式化机构距离
for (const i in institutionList) {
institutionList[i].distance = ctx.isEmpty(institutionList[i].area) ? 999999.0 : institutionList[i].area.distance;
}
institutionList = _.orderBy(institutionList, [ 'distance' ], [ 'asc' ]);
// 距离筛选
if (Number(distance) > 0) {
for (const i in institutionList) {
if (institutionList[i].distance > Number(distance)) {
institutionList = institutionList.slice(0, i);
break;
}
}
}
// 分页
const ret = {
results: [],
count: institutionList.length,
};
institutionList = institutionList.slice(Number(page - 1) * Number(limit), Number(page) * Number(limit));
institutionIds = R.pluck('id', institutionList);
// 获取所有分类
const allCats = await ctx.classModel.V4.CourseCat.findAll({ where: { status: 'online', is_deleted: 0 } });
const catList = [];
for (const v of allCats) {
catList[v.id] = v;
}
institutionCats = await ctx.classModel.V4.CourseInstitutionToCat.findAll({ where: { status: 'online', is_deleted: 0, institution_id: { $in: institutionIds } } });
// 获取所有标签
const allTags = await ctx.classModel.V4.CourseTag.findAll({ where: { status: 'online', is_deleted: 0 } });
const tagList = [];
for (const v of allTags) {
tagList[v.id] = v;
}
// 用户已收藏机构列表
const userInstitutions = await ctx.classModel.V4.CourseUserCollection.findAll({ where: { type: 1, is_deleted: 0, user_uuid: userUuid } });
const userInstitutionIds = R.pluck('type_id', userInstitutions);
// 机构图片及格式化
for (const i in institutionList) {
// 格式化机构分类(展示一级分类)
let cats = [];
for (const v of institutionCats) {
if (v.institution_id === institutionList[i].id && catList[v.cat_id]) {
if (catList[v.cat_id].parent_id === 0) {
cats.push(v.cat_id);
} else {
cats.push(catList[v.cat_id].parent_id);
}
}
}
// 去重
cats = _.uniq(cats);
institutionList[i].cats = [];
for (const v of cats) {
institutionList[i].cats.push(catList[v]);
}
// 标签
let tags = await ctx.classModel.V4.CourseInstitutionToTag.findAll({ where: { institution_id: institutionList[i].id, status: 'online', is_deleted: 0 } });
tags = _.orderBy(tags, [ 'sort' ], [ 'asc' ]);
institutionList[i].tags = [];
for (const v of tags) {
institutionList[i].tags.push(tagList[v.tag_id]);
}
// 优先获取机构详情图
let institutionImages = await ctx.classModel.V4.CourseImages.findAll({ where: { type: 1, type_id: institutionList[i].id, status: 'online', is_deleted: 0 }, order: [[ 'sort', 'asc' ]], limit: 3 });
if (institutionImages.length < 3) {
const defaultImages = await ctx.classModel.V4.CourseImages.findAll({ where: { type: 4, type_id: { $in: cats }, status: 'online', is_deleted: 0 }, limit: 3 - institutionImages.length });
institutionImages = institutionImages.concat(defaultImages);
}
institutionList[i].images = institutionImages;
institutionList[i].distance = String((institutionList[i].distance / 1000).toFixed(1)) + 'km';
institutionList[i].phone = institutionList[i].area.length > 0 ? institutionList[i].area[0].phone : '';
// 是否已收藏
institutionList[i].is_collected = userInstitutionIds.includes(institutionList[i].id) ? 1 : 0;
ret.results.push(institutionList[i]);
}
return ret;
}
// 搜索
async search(input) {
const { ctx } = this;
const { cat_id, age, search } = input;
const userUuid = ctx.userUuid;
// 保存搜索记录
if (search) {
const searchInfo = await ctx.classModel.V4.CourseSearch.findOne({ where: { content: search, is_deleted: 0 } });
if (searchInfo) {
await ctx.classModel.V4.CourseSearch.update({ count: searchInfo.count + 1 }, { where: { id: searchInfo.id } });
} else {
await ctx.classModel.V4.CourseSearch.create({ content: search, sort: 0, count: 1, is_hot: 0, status: 'online', is_deleted: 0, created_time: moment().format('YYYY-MM-DD HH:mm:ss'), updated_time: moment().format('YYYY-MM-DD HH:mm:ss') });
}
await ctx.classModel.V4.CourseUserSearch.create({ user_uuid: userUuid, content: search, status: 'online', created_time: moment().format('YYYY-MM-DD HH:mm:ss'), updated_time: moment().format('YYYY-MM-DD HH:mm:ss') });
}
let institutionList = [];
let institutionCats = [];
let institutionIds = [];
const filter = { where: { status: 'online', is_deleted: 0 }, row: true };
const classFilter = { where: { status: 'online', is_deleted: 0, name: { $like: '%' + search + '%' } }, attributes: [ 'id', 'institution_id', 'name', 'status', 'is_deleted' ], row: true };
const page_size = Number(input.page_size) || 10;
const offset = (page - 1) * page_size;
const attributes = [ 'id', 'institution_id', 'name', 'logo', 'age', 'price', 'price_type', 'mode', 'time', 'class_amount', 'multi_classes', 'cycle', 'description', 'sort' ];
const filter = { where: { status: 1, is_deleted: 0 }, order: [[ 'sort', 'asc' ], [ 'id', 'desc' ]], page_size, offset, attributes };
let filterIds = [];
let flag = false;
// 年龄筛选
if (Number(age) > 0) {
filter.where.min_age = { $lte: age };
filter.where.max_age = { $gte: age };
if (!ctx.isEmpty(input.age)) {
const filterByAge = await ctx.classModel.CourseV5ClassToAge.findAll({ where: { age_id: input.age, status: 1, is_deleted: 0 }, attributes: [ 'class_id' ] });
filterIds = R.pluck('class_id', filterByAge);
flag = true;
}
// 分类筛选
if (Number(cat_id) > 0) {
// 如果是一级分类,则需要加入该分类下所有子分类
const cats = await ctx.classModel.V4.CourseCat.findAll({ where: { parent_id: cat_id, status: 'online', is_deleted: 0 } });
const catIds = R.pluck('id', cats);
catIds.push(Number(cat_id));
institutionCats = await ctx.classModel.V4.CourseInstitutionToCat.findAll({ where: { status: 'online', is_deleted: 0, cat_id: { $in: catIds } } });
institutionIds = R.pluck('institution_id', institutionCats);
}
if (institutionIds.length > 0) {
filter.where.id = { $in: institutionIds };
classFilter.where.institution_id = { $in: institutionIds };
// 科目类型
if (!ctx.isEmpty(input.cat_id)) {
const filterByCategory = await ctx.classModel.CourseV5ClassToCat.findAll({ where: { cat_id: input.cate_id, status: 1, is_deleted: 0 }, attributes: [ 'class_id' ] });
filterIds = flag ? _.intersection(filterIds, R.pluck('class_id', filterByCategory)) : R.pluck('class_id', filterByCategory);
flag = true;
}
const institutionFilter = filter;
institutionFilter.where.name = { $like: '%' + search + '%' };
institutionList = await ctx.classModel.V4.CourseInstitution.findAll(institutionFilter);
const ids = R.pluck('id', institutionList);
// 课程搜索
const classList = await ctx.classModel.V4.CourseClass.findAll(classFilter);
// 去除已经搜到的机构
const classInstitutionIds = _.difference(R.pluck('institution_id', classList), ids);
if (classInstitutionIds.length > 0) {
filter.where.id = { $in: classInstitutionIds };
const classInstitutionList = await ctx.classModel.V4.CourseInstitution.findAll(filter);
institutionList = institutionList.concat(classInstitutionList);
// 课程状态
if (!ctx.isEmpty(input.mode)) {
filter.where.mode = input.mode;
}
institutionList = R.pluck('dataValues', institutionList);
const ret = await this.formatInstitutionList(institutionList, input);
return ret;
// 课程类型
if (!ctx.isEmpty(input.price_type)) {
filter.where.price_type = input.price_type;
}
// 获取热搜
async getHotSearch() {
const { ctx } = this;
const search = await ctx.classModel.V4.CourseSearch.findAll({ where: { status: 'online', is_deleted: 0, is_hot: 1 }, order: [[ 'sort', 'asc' ]] });
const ret = {
results: R.pluck('content', search),
count: search.length,
};
return ret;
if (flag) {
filter.where.id = { $in: filterIds };
}
const classList = await ctx.classModel.CourseV5Class.findAndCountAll(filter);
// 获取用户搜索历史
async getUserSearch() {
const { ctx } = this;
const userUuid = ctx.userUuid;
const search = await ctx.classModel.V4.CourseUserSearch.findAll({ where: { status: 'online', user_uuid: userUuid }, limit: 10, order: [[ 'id', 'desc' ]] });
const result = _.uniq(R.pluck('content', search));
const ret = {
results: result,
count: result.length,
};
return ret;
}
// 删除用户搜索历史
async deleteUserSearch() {
const { ctx } = this;
const userUuid = ctx.userUuid;
await ctx.classModel.V4.CourseUserSearch.update({ status: 'offline' }, { where: { user_uuid: userUuid, status: 'online' } });
return;
}
// 评论列表
async getComments(input) {
const { ctx } = this;
const page = Number(input.page) || 1;
const limit = Number(input.limit) || 10;
const offset = (page - 1) * limit;
const institution_id = Number(input.institution_id) || 0;
const comments = await ctx.classModel.V4.CourseComment.findAndCountAll({ where: { institution_id, status: 'online', is_deleted: 0 }, offset, limit, order: [[ 'id', 'desc' ]] });
comments.rows = R.pluck('dataValues', comments.rows);
const ret = {
results: await this.formatComments(comments.rows),
count: comments.count,
};
return ret;
}
// 格式化评论列表
async formatComments(comments) {
const { ctx } = this;
if (ctx.isEmpty(comments)) {
return [];
}
const ids = R.pluck('id', comments);
const images = await ctx.classModel.V4.CourseImages.findAll({ where: { type: 3, type_id: { $in: ids }, status: 'online', is_deleted: 0 } });
const ret = [];
for (const v of comments) {
// 评论图片
let commentImages = [];
for (const j of images) {
if (j.type_id === v.id) {
commentImages.push(j);
}
}
commentImages = _.orderBy(commentImages, [ 'sort' ], [ 'asc' ]);
ret.push({
id: v.id,
institution_id: v.institution_id,
user_uuid: v.user_uuid,
nickname: v.nickname,
avatar: v.avatar,
content: v.content,
has_image: v.has_image,
images: commentImages,
created_time: v.created_time,
});
}
return ret;
}
// 搜索关联
async getSuggestSearch(input) {
const { ctx } = this;
const { search } = input;
let results = [];
if (!ctx.isEmpty(search)) {
const institutions = await ctx.classModel.V4.CourseInstitution.findAll({ where: { status: 'online', is_deleted: 0, name: { $like: '%' + search + '%' } }, limit: 10, attributes: [ 'id', 'name', 'status', 'is_deleted' ] });
results = R.pluck('name', institutions);
}
const ret = {
results,
count: results.length,
};
return ret;
}
// 教师详情
async getTeacher(id) {
const { ctx } = this;
let teacher = await ctx.classModel.V4.CourseTeacher.findOne({ where: { id, status: 'online', is_deleted: 0 } });
if (ctx.isEmpty(teacher)) {
ctx.failed('数据不存在');
}
teacher = teacher.dataValues;
teacher.point_tags = teacher.point ? teacher.point.split(',') : [];
teacher.work_experience_tags = teacher.work_experience ? teacher.work_experience.split(';') : [];
const institution = await ctx.classModel.V4.CourseInstitution.findOne({ where: { id: teacher.institution_id } });
teacher.institution_name = institution.name;
return teacher;
}
// 教师列表
async getTeachers(input) {
const { ctx } = this;
const page = Number(input.page) || 1;
const limit = Number(input.limit) || 10;
const offset = (page - 1) * limit;
const institutionId = Number(input.institution_id) || 0;
const teachers = await ctx.classModel.V4.CourseTeacher.findAndCountAll({ where: { institution_id: institutionId, status: 'online', is_deleted: 0 }, raw: true, offset, limit });
const ret = {
results: teachers.rows,
count: teachers.count,
};
return ret;
}
// 课程列表
async getClasses(input) {
const { ctx } = this;
const page = Number(input.page) || 1;
const limit = Number(input.limit) || 10;
const offset = (page - 1) * limit;
const institutionId = Number(input.institution_id) || 0;
const inputClassIds = input.classIds || [];
const attributes = [ 'id', 'institution_id', 'name', 'type', 'class_price', 'min_age', 'max_age', 'status', 'is_deleted' ];
let classes = { rows: [], count: 0 };
if (institutionId > 0) {
classes = await ctx.classModel.V4.CourseClass.findAndCountAll({ where: { institution_id: institutionId, status: 'online', is_deleted: 0 }, raw: true, offset, limit, attributes });
} else if (inputClassIds.length > 0) {
classes = await ctx.classModel.V4.CourseClass.findAndCountAll({ where: { id: { $in: inputClassIds }, status: 'online', is_deleted: 0 }, raw: true, offset, limit, attributes });
}
const classIds = R.pluck('id', classes.rows);
// 课程图片
const classImages = await ctx.classModel.V4.CourseImages.findAll({ where: { type: 2, type_id: { $in: classIds }, status: 'online', is_deleted: 0 }, raw: true });
// 用户收藏的课程
const userCollection = await ctx.classModel.V4.CourseUserCollection.findAll({ where: { user_uuid: ctx.userUuid, is_deleted: 0, type: 2 }, raw: true });
const userCollection = await ctx.classModel.V5.CourseUserCollection.findAll({ where: { user_uuid: ctx.userUuid, is_deleted: 0, type: 3 }, raw: true });
const collectedIds = R.pluck('type_id', userCollection);
for (const i in classes.rows) {
let images = [];
for (const v of classImages) {
if (v.type_id === classes.rows[i].id) {
images.push(v);
}
}
images = _.orderBy(images, [ 'sort' ], [ 'asc' ]);
classes.rows[i].image = images.length > 0 ? images[0] : {};
classes.rows[i].is_collected = collectedIds.includes(classes.rows[i].id) ? 1 : 0;
classes.rows[i].age = classes.rows[i].min_age === 0 && classes.rows[i].max_age === 0 ? '' : `${classes.rows[i].min_age}-${classes.rows[i].max_age}岁`;
classes.rows[i].class_price = classes.rows[i].class_price || '到店咨询';
for (const i in classList.rows) {
classList.rows[i].is_collected = collectedIds.includes(classList.rows[i].id) ? 1 : 0;
}
const ret = {
results: classes.rows,
count: classes.count,
list: classList.rows,
total_count: classList.count,
page,
page_size,
};
return ret;
}
// 课程详情
async getClass(input) {
async getClassInfo(id) {
const { ctx } = this;
const classInfo = await ctx.classModel.V4.CourseClass.findOne({ where: { id: input.id, status: 'online', is_deleted: 0 }, raw: true });
const attributes = [ 'id', 'institution_id', 'name', 'logo', 'age', 'price', 'price_type', 'mode', 'time', 'class_amount', 'multi_classes', 'cycle', 'description', 'sort' ];
const classInfo = await ctx.classModel.V5.CourseV5Class.findOne({ where: { id, status: 1, is_deleted: 0 }, attributes, raw: true });
if (ctx.isEmpty(classInfo)) {
ctx.failed('数据不存在');
}
// 课程图片
let images = await ctx.classModel.V4.CourseImages.findAll({ where: { type: 2, type_id: input.id, status: 'online', is_deleted: 0 }, raw: true });
// 去重
images = _.uniqBy(images, function(v) { return (v.is_image === 1 ? v.image_url : v.video_url); });
images = _.orderBy(images, [ 'sort' ], [ 'asc' ]);
classInfo.images = images;
classInfo.class_price = ctx.isEmpty(classInfo.class_price) ? '' : classInfo.class_price + '元/课时';
input.institution_id = classInfo.institution_id;
const institution = await this.getInstitution(input);
classInfo.institution = ctx.isEmpty(institution) ? {} : institution.detail;
classInfo.area = ctx.isEmpty(institution) || ctx.isEmpty(institution.areas) ? {} : institution.areas[0];
const isCollected = await ctx.classModel.V4.CourseUserCollection.findOne({ where: { user_uuid: ctx.userUuid, type: 2, type_id: input.id, is_deleted: 0 } });
const isCollected = await ctx.classModel.V5.CourseUserCollection.findOne({ where: { user_uuid: ctx.userUuid, type: 3, type_id: id, is_deleted: 0 } });
classInfo.is_collected = ctx.isEmpty(isCollected) ? 0 : 1;
return classInfo;
}
// 用户收藏机构列表
async getUserCollectedInstitutions(input) {
const { ctx } = this;
const userUuid = ctx.userUuid;
const userCollection = await ctx.classModel.V4.CourseUserCollection.findAll({ where: { user_uuid: userUuid, is_deleted: 0, type: 1 }, raw: true });
const institutionIds = R.pluck('type_id', userCollection);
const institutionList = await ctx.classModel.V4.CourseInstitution.findAll({ where: { id: { $in: institutionIds }, status: 'online', is_deleted: 0 }, raw: true });
const ret = await this.formatInstitutionList(institutionList, input);
return ret;
// 额外字段
const classColumns = await ctx.classModel.V5.CourseV5ClassToColumn.findAll({ where: { class_id: id, status: 1, is_deleted: 0 } });
let columnList = await ctx.classModel.V5.CourseV5Column.findAll({ where: { id: { $in: R.pluck('column_id', classColumns) }, status: 1, is_deleted: 0 }, attributes: [ 'name' ] });
columnList = _.groupBy(columnList, 'id');
const columns = [];
for (const v of classColumns) {
if (!ctx.isEmpty(columnList[v.column_id])) {
columns.push({
id: v.column_id,
key: columnList[v.column_id][0].name,
value: v.value,
});
}
}
classInfo.columns = columns;
return classInfo;
}
// 用户收藏课程列表
async getUserCollectedClasses(input) {
const { ctx } = this;
const userUuid = ctx.userUuid;
const userCollection = await ctx.classModel.V4.CourseUserCollection.findAll({ where: { user_uuid: userUuid, is_deleted: 0, type: 2 }, raw: true });
const userCollection = await ctx.classModel.V5.CourseUserCollection.findAll({ where: { user_uuid: userUuid, is_deleted: 0, type: 2 }, raw: true });
const classIds = R.pluck('type_id', userCollection);
input.classIds = classIds;
......@@ -671,220 +107,7 @@ class InstitutionSubService extends Service {
return ret;
}
// 获取指定分类及子分类的选课指南
async getArticlesByCat(input) {
const { ctx } = this;
const page = Number(input.page) || 1;
const limit = Number(input.limit) || 2;
const offset = (page - 1) * limit;
const catId = Number(input.cat_id) || 0;
let catIds = [];
const filter = { where: { status: 'online', is_deleted: 0 }, order: [[ 'sort', 'asc' ], [ 'id', 'desc' ]], limit, offset };
// 获取子分类
if (catId > 0) {
const cats = await ctx.classModel.V4.CourseCat.findAll({ where: { parent_id: catId, status: 'online', is_deleted: 0 } });
catIds = R.pluck('id', cats);
catIds.push(catId);
filter.where.cat_id = { $in: catIds };
}
// 获取分类
const cats = await ctx.classModel.V4.CourseCat.findAll({ where: { status: 'online', is_deleted: 0 } });
const catMap = new Map();
for (const v of cats) {
catMap.set(v.id, v);
}
const articles = await ctx.classModel.V4.CourseArticle.findAndCountAll(filter);
const ret = [];
// 用户点赞列表
const userLikes = await ctx.classModel.V4.CourseLike.findAll({ where: { user_uuid: ctx.userUuid, type: 1, is_deleted: 0 } });
const userLikeIds = R.pluck('type_id', userLikes);
for (const v of articles.rows) {
ret.push({
id: v.id,
type: v.type,
cat_id: v.cat_id,
cat_title: catMap.has(v.cat_id) ? catMap.get(v.cat_id).name : '',
title: v.title,
description: v.description,
content: v.content,
image: v.image,
source: v.source,
like_count: v.like_count,
read_count: v.read_count,
sort: v.sort,
is_like: userLikeIds.includes(v.id) ? 1 : 0,
created_time: v.created_time,
});
}
return { results: ret, count: articles.count, page };
}
// 获取选课指南
async getArticle(id) {
const { ctx } = this;
const article = await ctx.classModel.V4.CourseArticle.findOne({ where: { id, status: 'online', is_deleted: 0 } });
if (ctx.isEmpty(article)) {
ctx.failed('数据不存在');
}
await ctx.classModel.V4.CourseArticle.update({ read_count: sequelize.literal('`read_count` + 1') }, { where: { id } });
// 用户是否点赞
const userLike = await ctx.classModel.V4.CourseLike.findOne({ where: { user_uuid: ctx.userUuid, type: 1, type_id: id, is_deleted: 0 } });
// 获取分类
const cats = await ctx.classModel.V4.CourseCat.findAll({ where: { status: 'online', is_deleted: 0 } });
const catMap = new Map();
for (const v of cats) {
catMap.set(v.id, v);
}
// 获取关联列表
let relations = [];
if (!ctx.isEmpty(article.relations)) {
const ids = article.relations.split(',');
relations = await ctx.classModel.V4.CourseArticle.findAll({ where: { id: { $in: ids }, status: 'online', is_deleted: 0 }, order: [[ 'sort', 'asc' ], [ 'id', 'desc' ]], attributes: [ 'id', 'title', 'type', 'image', 'read_count' ] });
}
const ret = {
id: article.id,
type: article.type,
cat_id: article.cat_id,
cat_title: catMap.has(article.cat_id) ? catMap.get(article.cat_id).name : '',
title: article.title,
description: article.description,
content: article.content,
image: article.image,
source: article.source,
like_count: article.like_count,
read_count: article.read_count,
sort: article.sort,
relations,
is_like: ctx.isEmpty(userLike) ? 0 : 1,
created_time: article.created_time,
};
return ret;
}
// 点赞 1:选课指南;
async like(input) {
const { ctx } = this;
const type = Number(input.type) || 0;
const typeId = Number(input.type_id) || 0;
let tmp = {};
if (type === 0 || typeId === 0) {
ctx.failed('参数异常');
}
// 是否重复点赞
tmp = await ctx.classModel.V4.CourseLike.findOne({ where: { user_uuid: ctx.userUuid, type, type_id: typeId, is_deleted: 0 } });
if (!ctx.isEmpty(tmp)) {
ctx.failed('请勿重复点赞');
}
// 校验点赞对象是否存在
switch (type) {
case 1:
tmp = await ctx.classModel.V4.CourseArticle.findOne({ where: { id: typeId, status: 'online', is_deleted: 0 } });
if (ctx.isEmpty(tmp)) {
ctx.failed('数据不存在');
}
// 更新点赞数
await ctx.classModel.V4.CourseArticle.update({ like_count: sequelize.literal('`like_count` + 1') }, { where: { id: typeId } });
break;
default:
break;
}
await ctx.classModel.V4.CourseLike.create({ user_uuid: ctx.userUuid, type, type_id: typeId, is_deleted: 0, created_time: moment().format('YYYY-MM-DD HH:mm:ss') });
return;
}
// 取消点赞
async unlike(input) {
const { ctx } = this;
const type = Number(input.type) || 0;
const typeId = Number(input.type_id) || 0;
let tmp = {};
if (type === 0 || typeId === 0) {
ctx.failed('参数异常');
}
// 是否重复点赞
const userLike = await ctx.classModel.V4.CourseLike.findOne({ where: { user_uuid: ctx.userUuid, type, type_id: typeId, is_deleted: 0 } });
if (ctx.isEmpty(userLike)) {
ctx.failed('尚未点赞');
}
// 校验点赞对象是否存在
switch (type) {
case 1:
tmp = await ctx.classModel.V4.CourseArticle.findOne({ where: { id: typeId, status: 'online', is_deleted: 0 } });
if (ctx.isEmpty(tmp)) {
ctx.failed('数据不存在');
}
// 更新点赞数
await ctx.classModel.V4.CourseArticle.update({ like_count: sequelize.literal('`like_count` - 1') }, { where: { id: typeId } });
break;
default:
break;
}
await ctx.classModel.V4.CourseLike.update({ is_deleted: 1 }, { where: { id: userLike.id } });
return;
}
// 获取选课指南推荐列表
async getArticlesByRecommend(input) {
const { ctx } = this;
const page = Number(input.page) || 1;
const limit = Number(input.limit) || 2;
const offset = (page - 1) * limit;
const articles = await ctx.classModel.V4.CourseArticle.findAndCountAll({ where: { is_recommend: 1, status: 'online', is_deleted: 0 }, order: [[ 'sort', 'asc' ], [ 'id', 'desc' ]], limit, offset });
// 获取分类
const cats = await ctx.classModel.V4.CourseCat.findAll({ where: { status: 'online', is_deleted: 0 } });
const catMap = new Map();
for (const v of cats) {
catMap.set(v.id, v);
}
const ret = [];
// 用户点赞列表
const userLikes = await ctx.classModel.V4.CourseLike.findAll({ where: { user_uuid: ctx.userUuid, type: 1, is_deleted: 0 } });
const userLikeIds = R.pluck('type_id', userLikes);
for (const v of articles.rows) {
ret.push({
id: v.id,
type: v.type,
cat_id: v.cat_id,
cat_title: catMap.has(v.cat_id) ? catMap.get(v.cat_id).name : '',
title: v.title,
description: v.description,
content: v.content,
image: v.image,
source: v.source,
like_count: v.like_count,
read_count: v.read_count,
sort: v.sort,
is_like: userLikeIds.includes(v.id) ? 1 : 0,
created_time: v.created_time,
});
}
return { results: ret, count: articles.count, page };
}
//
}
module.exports = InstitutionSubService;
......@@ -46,17 +46,27 @@ class OptionService extends Service {
return options;
}
async getBanners(alias) {
async getBannerList(alias) {
const { ctx } = this;
const bannerType = await ctx.classModel.V5.CourseBannerType.findOne({ where: { alias, status: 'online', is_deleted: 0 }, row: true });
const bannerType = await ctx.classModel.V5.CourseBannerType.findOne({ where: { alias, status: 1, is_deleted: 0 }, row: true });
if (ctx.isEmpty(bannerType)) {
ctx.failed('数据不存在');
}
const banners = await ctx.classModel.V5.CourseBanner.findAll({ where: { type_id: bannerType.id, status: 'online', is_deleted: 0 }, order: [[ 'sort', 'asc' ]], row: true });
const banners = await ctx.classModel.V5.CourseBanner.findAll({ where: { type_id: bannerType.id, status: 1, is_deleted: 0 }, order: [[ 'sort', 'asc' ]], row: true });
const results = [];
for (const v of banners) {
results.push({
id: v.id,
title: v.title,
url: v.url,
link: v.link,
created_time: v.created_time,
});
}
const ret = {
results: banners,
count: banners.length,
list: results,
};
return ret;
......@@ -84,9 +94,19 @@ class OptionService extends Service {
parent_id: v.parent_id,
name: v.name,
selected_icon: v.selected_icon,
unselected_icon: v.unselected_icon,
sort: v.sort,
});
}
const ret = {
list: results,
};
return ret;
}
}
module.exports = OptionService;
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