提交 02f511b8 authored 作者: 王鹏飞's avatar 王鹏飞

update

上级 cc29b4f4
NODE_ENV=production
VUE_APP_LOGIN_API=https://e-learning3.ezijing.com
VUE_APP_BASE_API=https://alumni-api.ezijing.com
VUE_APP_LOGIN_API=https://databus-api2.ezijing.com
VUE_APP_BASE_API=https://lms-api.ezijing.com
VUE_APP_LOGIN_API=https://e-learning.ezijing.com
VUE_APP_BASE_API=https://alumni-api.ezijing.com
......@@ -5,13 +5,16 @@
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"dev-build": "vue-cli-service build --mode dev",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.19.2",
"core-js": "^3.6.4",
"dayjs": "^1.8.23",
"md5": "^2.2.1",
"qs": "^6.9.1",
"timeago.js": "^4.0.2",
"vant": "^2.5.5",
"vue": "^2.6.11",
"vue-meta": "^2.3.3",
......
public/favicon.ico

4.2 KB | W: | H:

public/favicon.ico

16.6 KB | W: | H:

public/favicon.ico
public/favicon.ico
public/favicon.ico
public/favicon.ico
  • 2-up
  • Swipe
  • Onion skin
import httpRequest from '@/utils/axios'
// 上传文件
export function upload(data) {
return httpRequest({
url: '/v1/activities/tools/upload',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
},
data
})
}
// 获取热门推荐列表
export function getHotList(params) {
return httpRequest({
url: '/v1/activities/hotest',
method: 'get',
params
})
}
// 获取我参与的列表
export function getJoinList(params) {
return httpRequest({
url: '/v1/activities/my/participanted',
method: 'get',
params
})
}
// 获取我发起的列表
export function getPublishList(params) {
return httpRequest({
url: '/v1/activities/my/initiated',
method: 'get',
params
})
}
// 获取活动详情
export function getActivity(id) {
return httpRequest({
url: `/v1/activities/${id}`,
method: 'get'
})
}
// 报名活动
export function joinActivity(data) {
return httpRequest({
url: '/v1/activities/join',
method: 'post',
data
})
}
// 创建活动
export function createActivity(data) {
return httpRequest({
url: '/v1/activities/create',
method: 'post',
data
})
}
......@@ -127,8 +127,8 @@ body {
cursor: pointer;
}
.empty {
margin-top: 100px;
padding-top: 140px;
margin-top: 45px;
padding-top: 130px;
font-size: 15px;
color: #333;
background: url('~@/assets/img/icon_warning.png') no-repeat center top;
......
......@@ -2,6 +2,7 @@
<van-form
ref="form"
class="form"
label-width="100%"
validate-trigger="onChange"
v-bind="$attrs"
v-on="$listeners"
......@@ -16,7 +17,7 @@
:border="false"
v-bind="item"
v-model="ruleForm[item.name]"
@click="showPicker('datetime', item.name)"
@click="showPicker(item)"
/>
</template>
<!-- 选择 -->
......@@ -25,19 +26,42 @@
readonly
clickable
:border="false"
:value="getPickerValue(item.name, ruleForm[item.name])"
v-bind="item"
v-model="ruleForm[item.name]"
@click="showPicker('select', item.name)"
@click="showPicker(item)"
/>
</template>
<!-- 上传图片 -->
<van-field
:border="false"
:label="item.label"
v-bind="item"
v-model="ruleForm[item.name]"
v-else-if="item.fieldType === 'uploader'"
>
<template #input>
<van-uploader v-model="ruleForm[item.name]" />
<upload v-model="ruleForm[item.name]" :max-count="1" />
</template>
</van-field>
<!-- 上传图片 -->
<van-field
:border="false"
v-bind="item"
v-model="ruleForm[item.name]"
v-else-if="item.fieldType === 'radio'"
>
<template #input>
<van-radio-group
v-model="ruleForm[item.name]"
direction="horizontal"
>
<van-radio
:name="item.name"
v-for="item in item.values"
:key="item.name"
>
{{ item.text }}
</van-radio>
</van-radio-group>
</template>
</van-field>
<!-- 文本框 -->
......@@ -47,22 +71,21 @@
v-model="ruleForm[item.name]"
v-else
/>
<!-- 时间选择器 -->
<van-popup v-model="pickerVisible" position="bottom">
<van-popup v-model="picker.visible" position="bottom">
<van-datetime-picker
type="datetime"
:value="pickerValue"
:value="picker.value"
:min-date="minDate"
@confirm="onTimePickerConfirm"
@cancel="pickerVisible = false"
v-if="pickerValue === 'datetime'"
@cancel="picker.visible = false"
v-if="picker.type === 'datetime'"
/>
<van-picker
show-toolbar
:columns="columns"
:columns="picker.values"
@confirm="onPickerConfirm"
@cancel="pickerVisible = false"
v-if="pickerValue === 'select'"
@cancel="picker.visible = false"
v-if="picker.type === 'select'"
/>
</van-popup>
</div>
......@@ -71,10 +94,14 @@
</template>
<script>
import dayjs from 'dayjs'
import Upload from '@/components/Upload'
export default {
name: 'VForm',
components: { Upload },
props: {
params: {
model: {
type: Object,
default() {
return {}
......@@ -88,36 +115,78 @@ export default {
}
}
},
watch: {
model: {
immediate: true,
deep: true,
handler(value) {
this.ruleForm = value
}
}
},
data() {
return {
ruleForm: this.params,
pickerVisible: false,
pickerType: '',
pickerName: '',
pickerValue: '',
minDate: new Date()
ruleForm: this.model,
picker: {
visible: false,
type: '',
name: '',
value: '',
valueKey: 'name',
values: [],
remote: null
},
minDate: new Date(),
pickerActive: {}
}
},
methods: {
showPicker(fieldType, name) {
this.pickerVisible = true
this.pickerValue = this.ruleForm[name]
getPickerValue(name, value) {
const field = this.fields.find(item => item.name === name)
const found = field.values.find(item => item[field.valueKey] === value)
return found ? found.text : ''
},
showDatetimePicker(name) {
this.pickerVisible = true
this.pickerName = name
this.pickerValue = this.ruleForm[name]
showPicker({ fieldType, name, remote, values = [], valueKey = 'name' }) {
this.picker.visible = true
this.picker.name = name
this.picker.type = fieldType
this.picker.value = this.ruleForm[name]
if (fieldType === 'select') {
this.picker.valueKey = valueKey
this.picker.values = values
if (remote) {
this.picker.remote = remote
this.getSelectList(remote)
}
}
},
onTimePickerConfirm(time) {
this.ruleForm[this.pickerName] = time
this.pickerVisible = false
onPickerConfirm(data) {
this.ruleForm[this.picker.name] = data[this.picker.valueKey]
this.picker.visible = false
if (this.picker.remote && this.picker.remote.change) {
this.pickerActive = this.pickerList.find(
item => item[this.picker.remote.valueKey] === data
)
}
},
onPickerConfirm(value) {
this.ruleForm[this.pickerName] = value
this.pickerVisible = false
onTimePickerConfirm(time) {
this.ruleForm[this.picker.name] = dayjs(time)
.second(0)
.format('YYYY-MM-DD HH:mm:ss')
this.picker.visible = false
},
submit() {
return this.$refs.form.submit()
},
getSelectList(remote) {
if (!remote) {
return
}
remote.request(this.pickerActive).then(response => {
const data = response.data
this.pickerList = data
this.pickerColumns = data.map(item => item[remote.valueKey])
})
}
}
}
......
<template>
<div class="card" @click="onClick">
<div class="card-main">
<div class="card-title">{{ data.title }}</div>
<div class="card-title">{{ data.activity_name }}</div>
<div class="card-publish">
<div class="card-user">
<div class="card-user__avatar"></div>
<div class="card-user__nickname">赵瑾龙</div>
<div class="card-user__avatar">
<img :src="data.initiator.avatar" />
</div>
<div class="card-publish__time">44分钟前</div>
<div class="card-user__nickname">{{ data.initiator.nickname }}</div>
</div>
<div class="card-publish__time">{{ datetimeText }}</div>
</div>
</div>
<div class="card-pic" v-if="data.activity_image">
<img :src="data.activity_image" />
</div>
<div class="card-pic"></div>
</div>
</template>
<script>
import { format } from 'timeago.js'
export default {
name: 'Card',
props: { data: Object },
computed: {
datetimeText() {
return format(this.data.created_time, 'zh_CN')
}
},
methods: {
onClick() {
this.$router.push({ name: 'item', query: this.$route.query })
this.$router.push({ name: 'item', params: { id: this.data.id } })
}
}
}
......@@ -57,6 +67,10 @@ export default {
background-color: #ccc;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
.card-user__nickname {
padding-left: 10px;
......
<template>
<div class="card" @click="onClick">
<div class="card-hd">
<div class="card-title">{{ data.activity_name }}</div>
<div class="card-tools">
<span class="status">已报名</span>
</div>
</div>
<div class="card-main">
<div class="p-item">
<div class="p-title">时间:</div>
<div class="p-content" style="color:#333;">
{{ data.activity_time }}
</div>
</div>
<div class="p-item">
<div class="p-title">地点:</div>
<div class="p-content">
{{ data.activity_city }}-{{ data.activity_address }}
</div>
</div>
<div class="p-item">
<div class="p-title">发起人:</div>
<div class="p-content">{{ data.initiator.nickname }}</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'JoinCard',
props: { data: Object },
computed: {},
methods: {
onClick() {
this.$router.push({ name: 'item', params: { id: this.data.id } })
}
}
}
</script>
<style lang="scss" scoped>
.card {
margin: 15px 0 20px;
padding: 10px 20px 20px;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.06);
}
.card-hd {
display: flex;
}
.card-title {
flex: 1;
font-size: 15px;
color: #333;
}
.card-tools {
padding-left: 10px;
.status {
font-size: 15px;
color: #67c23a;
}
}
.p-item {
margin-top: 10px;
display: flex;
}
.p-title {
font-size: 12px;
color: #999;
}
.p-content {
font-size: 12px;
color: #999;
}
</style>
<template>
<div class="card" @click="onClick">
<div class="card-hd">
<div class="card-title">{{ data.activity_name }}</div>
<div class="card-tools">
<span class="status">已报名</span>
</div>
</div>
<div class="card-main">
<div class="p-item">
<div class="p-title">时间:</div>
<div class="p-content" style="color:#333;">
{{ data.activity_time }}
</div>
</div>
<div class="p-item">
<div class="p-title">地点:</div>
<div class="p-content">
{{ data.activity_city }}-{{ data.activity_address }}
</div>
</div>
<div class="p-item">
<div class="p-title">发起人:</div>
<div class="p-content">{{ data.initiator.nickname }}</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'JoinedCard',
props: { data: Object },
computed: {},
methods: {
onClick() {
this.$router.push({ name: 'item', params: { id: this.data.id } })
}
}
}
</script>
<style lang="scss" scoped>
.card {
margin: 15px 0 20px;
padding: 10px 20px 20px;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.06);
}
.card-hd {
display: flex;
}
.card-title {
flex: 1;
font-size: 15px;
color: #333;
}
.card-tools {
padding-left: 10px;
.status {
font-size: 15px;
color: #67c23a;
}
}
.p-item {
margin-top: 10px;
display: flex;
}
.p-title {
font-size: 12px;
color: #999;
}
.p-content {
font-size: 12px;
color: #999;
}
</style>
......@@ -7,13 +7,13 @@
<span></span><span></span><span></span>
</div>
<ul class="menu-list">
<li @click="toPage({ name: 'list', query: { tab: '0' } })">
<li @click="toPage({ name: 'index', query: { tab: '0' } })">
热门推荐
</li>
<li @click="toPage({ name: 'list', query: { tab: '1' } })">
<li @click="toPage({ name: 'index', query: { tab: '1' } })">
我参与的
</li>
<li @click="toPage({ name: 'list', query: { tab: '2' } })">
<li @click="toPage({ name: 'index', query: { tab: '2' } })">
我发起的
</li>
<li @click="$router.back()">返回上一页</li>
......@@ -43,7 +43,7 @@ export default {
this.menuVisible = false
this.$router.push({
name: route.name,
query: Object.assign({}, this.$route.query, route.query)
query: route.query
})
}
}
......@@ -56,15 +56,22 @@ export default {
}
.menu .inner {
position: fixed;
top: 0;
left: 0;
top: 0;
right: 0;
min-width: 70px;
max-width: 750px;
height: 60px;
padding: 20px 30px;
margin: 0 auto;
padding: 0 30px;
z-index: 100;
display: flex;
align-items: center;
justify-content: flex-end;
background-color: #fff;
max-width: 750px;
margin: 0 auto;
// border-top-left-radius: 30px;
// border-bottom-left-radius: 30px;
// box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.06);
}
.menu.is-show {
.menu-list {
......@@ -81,8 +88,6 @@ export default {
}
}
.menu-icon {
position: absolute;
right: 30px;
width: 20px;
height: 18px;
cursor: pointer;
......@@ -99,7 +104,7 @@ export default {
.menu-list {
position: absolute;
top: 20px;
right: 25px;
right: 20px;
display: none;
margin-top: 30px;
width: 180px;
......
<template>
<div class="card" @click="onClick">
<div class="card-hd">
<div class="card-title">{{ data.activity_name }}</div>
<div class="card-tools">
<span class="status" :class="{ 'is-green': isPass }">
{{ statusText }}
</span>
</div>
</div>
<div class="card-main">
<div class="p-item">
<div class="p-title">时间:</div>
<div class="p-content" style="color:#333;">
{{ data.activity_time }}
</div>
</div>
<div class="p-item">
<div class="p-title">地点:</div>
<div class="p-content">
{{ data.activity_city }}-{{ data.activity_address }}
</div>
</div>
<div class="p-item">
<div class="p-title">发起人:</div>
<div class="p-content">{{ data.initiator.nickname }}</div>
</div>
<div class="p-item" v-if="data.approve_remark">
<div class="p-title">备注:</div>
<div class="p-content is-red">{{ data.approve_remark }}</div>
</div>
</div>
<div class="card-ft" v-if="data.participant_count">
<div class="join-button" @click.stop="toJoinPage">
{{ data.participant_count }}人已报名,去查看
</div>
</div>
</div>
</template>
<script>
export default {
name: 'JoinCard',
props: { data: Object },
computed: {
statusText() {
const map = {
'-1': '待审核',
'0': '审核未通过',
'1': '已发布'
}
return map[this.data.approve_status]
},
isPass() {
return this.data.approve_status === '1'
}
},
methods: {
onClick() {
this.$router.push({ name: 'item', params: { id: this.data.id } })
},
toJoinPage() {
this.$router.push({ name: 'create', params: { id: this.data.id } })
}
}
}
</script>
<style lang="scss" scoped>
.card {
margin: 15px 0 20px;
padding: 10px 20px 20px;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.06);
}
.card-hd {
display: flex;
}
.card-title {
flex: 1;
font-size: 15px;
color: #333;
}
.card-tools {
padding-left: 10px;
.status {
font-size: 15px;
color: #999;
}
}
.p-item {
margin-top: 10px;
display: flex;
}
.p-title {
font-size: 12px;
color: #999;
}
.p-content {
font-size: 12px;
color: #999;
}
.is-red {
color: #ab2824 !important;
}
.is-green {
color: #67c23a !important;
}
.card-ft {
margin: 10px -30px -20px;
padding: 10px 20px;
text-align: right;
border-top: 1px solid #f5f5f5;
.join-button {
display: inline-block;
padding: 0 20px;
font-size: 12px;
color: #999;
line-height: 26px;
border: 1px solid #999;
border-radius: 4px;
cursor: pointer;
}
}
</style>
<template>
<van-uploader
v-model="fileList"
:after-read="afterRead"
@delete="onDelete"
v-bind="$attrs"
/>
</template>
<script>
import { upload } from '@/api/index'
export default {
name: 'Upload',
props: { value: String },
data() {
return { fileList: [] }
},
watch: {
value: {
immediate: true,
handler(value) {
this.fileList = value ? [{ url: value }] : []
}
}
},
methods: {
afterRead(file) {
file.status = 'uploading'
file.message = '上传中...'
let formData = new FormData()
formData.append('file', file.file)
upload(formData)
.then(response => {
if (response.success) {
file.status = 'done'
this.$emit('input', response.url)
} else {
file.status = 'failed'
file.message = '上传失败'
}
})
.catch(() => {
file.status = 'failed'
file.message = '上传失败'
})
},
onDelete() {
this.$emit('input', '')
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .van-uploader__upload {
width: 150px;
height: 80px;
background-color: #e0e0e0;
border-radius: 0;
}
::v-deep .van-uploader__upload-icon {
color: #666;
}
</style>
......@@ -44,6 +44,9 @@ Vue.use(RadioGroup)
import { DatetimePicker } from 'vant'
Vue.use(DatetimePicker)
import { Picker } from 'vant'
Vue.use(Picker)
import { Uploader } from 'vant'
Vue.use(Uploader)
......
......@@ -5,37 +5,87 @@ import Layout from '@/components/Layout.vue'
Vue.use(VueRouter)
const routes = [
{ path: '*', redirect: '/list' },
{ path: '/', redirect: '/list' },
{ path: '*', redirect: '/' },
{
name: 'login',
path: '/login',
component: () => import('@/views/Login.vue')
},
// 首页
{
name: 'list',
path: '/list',
component: () => import('@/views/List.vue')
name: 'index',
path: '/',
component: () => import('@/views/Index.vue')
},
// 创建
{
path: '/item',
path: '/create',
component: Layout,
children: [
{
name: 'create',
path: '',
component: () => import('@/views/Create.vue')
}
]
},
// 修改
{
path: '/edit/:id',
component: Layout,
children: [
{
name: 'edit',
path: '',
component: () => import('@/views/Edit.vue')
}
]
},
// 详情
{
path: '/item/:id',
component: Layout,
children: [
{
name: 'item',
path: '',
name: 'item',
component: () => import('@/views/Item.vue')
}
]
},
// 全部回复
{
path: '/create',
path: '/comment/:id',
component: Layout,
children: [
{
name: 'create',
path: '',
component: () => import('@/views/Create.vue')
name: 'comment',
component: () => import('@/views/Comment.vue')
}
]
},
// 加入活动
{
path: '/join/:id',
component: Layout,
children: [
{
path: '',
name: 'join',
component: () => import('@/views/Join.vue')
}
]
},
// 查看已加入
{
path: '/joined/:id',
component: Layout,
children: [
{
path: '',
name: 'joined',
component: () => import('@/views/Joined.vue')
}
]
}
......
import axios from 'axios'
import qs from 'qs'
import { Toast } from 'vant'
import { Notify } from 'vant'
import router from '@/router'
const httpRequest = axios.create({
// baseURL: process.env.VUE_APP_BASE_API,
baseURL: process.env.VUE_APP_BASE_API,
timeout: 60000,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
// 请求拦截
httpRequest.interceptors.request.use(
function(config) {
const token = localStorage.getItem('token') || ''
if (token) {
config.headers.token = token
}
if (
config.headers['Content-Type'] === 'application/x-www-form-urlencoded'
) {
......@@ -31,15 +38,17 @@ httpRequest.interceptors.response.use(
},
function(error) {
if (error.response) {
const { status } = error.response.data
if (status === 403) {
const { status, message } = error.response.data
if (status === 400 || status === 404) {
Notify(message)
} else if (status === 403) {
router.replace({
path: '/login',
query: { redirect_uri: encodeURIComponent(window.location.href) }
})
}
} else {
Toast({ type: 'error', message: error })
Notify(error)
}
return Promise.reject(error)
}
......
<template>
<div class="main"></div>
</template>
<script>
export default {
metaInfo: {
title: '全部回复'
},
data() {
return {}
},
computed: {
pid() {
return this.$route.params.id
}
}
}
</script>
<style lang="scss" scoped></style>
......@@ -3,7 +3,7 @@
<v-form ref="form" :fields="page.form.fields" @submit="onSubmit"></v-form>
<div class="fixed-box">
<div class="fixed-inner">
<div class="fixed-button" @click="onSubmit">发布</div>
<div class="fixed-button" @click="handleSubmit">发布</div>
</div>
</div>
</div>
......@@ -11,14 +11,14 @@
<script>
import VForm from '@/components/Form'
import * as api from '@/api/index'
const pages = {
0: {
10: {
title: '发布活动',
form: {
fields: [
{
name: 'title',
name: 'activity_name',
label: '主题',
required: true,
placeholder: '请输入活动主题',
......@@ -26,35 +26,36 @@ const pages = {
},
{
fieldType: 'uploader',
name: 'uploader',
name: 'activity_image',
label: '封面',
placeholder: '请上传活动封面'
},
{
type: 'textarea',
name: 'content',
name: 'activity_contents',
label: '内容',
required: true,
placeholder: '请输入活动内容',
autosize: { maxHeight: 120, minHeight: 120 },
rules: [{ required: true, message: '请输入活动内容' }]
},
{
fieldType: 'datetime',
name: 'time',
name: 'activity_time',
label: '时间',
required: true,
placeholder: '请选择活动时间',
rules: [{ required: true, message: '请选择活动时间' }]
},
{
name: 'city',
name: 'activity_city',
label: '城市',
required: true,
placeholder: '请输入活动城市',
rules: [{ required: true, message: '请输入活动城市' }]
},
{
name: 'address',
name: 'activity_address',
label: '具体地址',
required: true,
placeholder: '请输入活动具体地址',
......@@ -62,7 +63,7 @@ const pages = {
},
{
type: 'digit',
name: 'count',
name: 'participator_limit',
label: '希望人数',
required: true,
placeholder: '请输入希望人数',
......@@ -71,7 +72,7 @@ const pages = {
]
}
},
1: {
20: {
title: '发布需求',
form: {
fields: [
......@@ -81,10 +82,16 @@ const pages = {
label: '类型',
required: true,
placeholder: '请选择需求类型',
rules: [{ required: true, message: '请选择需求类型' }]
rules: [{ required: true, message: '请选择需求类型' }],
values: [
{ name: '0', text: '行业资讯' },
{ name: '1', text: '就业招聘' },
{ name: '2', text: '需求对接' }
],
valueKey: 'name'
},
{
name: 'title',
name: 'activity_name',
label: '主题',
required: true,
placeholder: '请输入需求主题',
......@@ -92,10 +99,11 @@ const pages = {
},
{
type: 'textarea',
name: 'content',
name: 'activity_contents',
label: '内容',
required: true,
placeholder: '请输入需求内容',
autosize: { maxHeight: 160, minHeight: 120 },
rules: [{ required: true, message: '请输入需求内容' }]
}
]
......@@ -115,14 +123,27 @@ export default {
return {}
},
computed: {
publishType() {
return this.$route.query.publish_type || '10'
},
page() {
const publishType = this.$route.query.publish_type || '0'
return pages[publishType] || {}
return pages[this.publishType] || {}
}
},
methods: {
onSubmit() {
handleSubmit() {
this.$refs.form.submit()
},
onSubmit() {
let data = this.$refs.form.ruleForm
data.activity_type = this.publishType
api.createActivity(data).then(() => {
this.$dialog
.alert({ confirmButtonText: '确定', message: '提交成功' })
.then(() => {
this.$router.push({ name: 'index', query: this.$route.query })
})
})
}
}
}
......
<template>
<div class="main">
<v-form
ref="form"
:model="formModel"
:fields="page.form.fields"
@submit="onSubmit"
></v-form>
<div class="fixed-box">
<div class="fixed-inner">
<div class="fixed-button" @click="handleSubmit">提交</div>
</div>
</div>
</div>
</template>
<script>
import VForm from '@/components/Form'
import * as api from '@/api/index'
const pages = {
10: {
title: '编辑活动',
form: {
fields: [
{
name: 'activity_name',
label: '主题',
required: true,
placeholder: '请输入活动主题',
rules: [{ required: true, message: '请输入活动主题' }]
},
{
fieldType: 'uploader',
name: 'activity_image',
label: '封面',
placeholder: '请上传活动封面'
},
{
type: 'textarea',
name: 'activity_contents',
label: '内容',
required: true,
placeholder: '请输入活动内容',
autosize: { maxHeight: 120, minHeight: 120 },
rules: [{ required: true, message: '请输入活动内容' }]
},
{
fieldType: 'datetime',
name: 'activity_time',
label: '时间',
required: true,
placeholder: '请选择活动时间',
rules: [{ required: true, message: '请选择活动时间' }]
},
{
name: 'activity_city',
label: '城市',
required: true,
placeholder: '请输入活动城市',
rules: [{ required: true, message: '请输入活动城市' }]
},
{
name: 'activity_address',
label: '具体地址',
required: true,
placeholder: '请输入活动具体地址',
rules: [{ required: true, message: '请输入活动具体地址' }]
},
{
type: 'digit',
name: 'participator_limit',
label: '希望人数',
required: true,
placeholder: '请输入希望人数',
rules: [{ required: true, message: '请输入希望人数' }]
}
]
}
},
20: {
title: '编辑需求',
form: {
fields: [
{
fieldType: 'select',
name: 'type',
label: '类型',
required: true,
placeholder: '请选择需求类型',
rules: [{ required: true, message: '请选择需求类型' }],
values: [
{ name: '0', text: '行业资讯' },
{ name: '1', text: '就业招聘' },
{ name: '2', text: '需求对接' }
],
valueKey: 'name'
},
{
name: 'activity_name',
label: '主题',
required: true,
placeholder: '请输入需求主题',
rules: [{ required: true, message: '请输入需求主题' }]
},
{
type: 'textarea',
name: 'activity_contents',
label: '内容',
required: true,
placeholder: '请输入需求内容',
autosize: { maxHeight: 160, minHeight: 120 },
rules: [{ required: true, message: '请输入需求内容' }]
}
]
}
}
}
export default {
name: 'Create',
components: { VForm },
metaInfo() {
return {
title: this.page.title
}
},
data() {
return {
formModel: {}
}
},
computed: {
publishType() {
return this.formModel.activity_type || '10'
},
page() {
return pages[this.publishType] || {}
},
pid() {
return this.$route.params.id
}
},
methods: {
handleSubmit() {
this.$refs.form.submit()
},
onSubmit() {
let data = this.$refs.form.ruleForm
data.activity_type = this.publishType
api.createActivity(data).then(() => {
this.$dialog
.alert({ confirmButtonText: '确定', message: '提交成功' })
.then(() => {
this.$router.push({ name: 'index', query: this.$route.query })
})
})
},
getDetail() {
const toast = this.$toast.loading({
message: '加载中...',
forbidClick: true,
duration: 0
})
api.getActivity(this.pid).then(response => {
this.formModel = response.form
toast.clear()
})
}
}
}
</script>
<style lang="scss"></style>
<template>
<div class="list">
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
v-if="list.length"
>
<hot-card v-for="item in list" :data="item" :key="item.id"></hot-card>
</van-list>
<div class="empty" v-else>暂无热门推荐</div>
</div>
</template>
<script>
import * as api from '@/api/index'
import HotCard from '@/components/HotCard'
export default {
components: { HotCard },
data() {
return {
list: [],
loading: false,
finished: false,
page: { offset: 0, limit: 10 }
}
},
methods: {
getList() {
this.loading = true
api
.getHotList(this.page)
.then(response => {
if (response.length) {
this.list = this.list.concat(response)
}
this.loading = false
this.finished = response.length < this.page.limit
})
.catch(() => {
this.loading = false
this.finished = true
})
},
onLoad() {
this.page.offset++
this.getList()
}
},
beforeMount() {
this.getList()
}
}
</script>
<template>
<div class="list">
<van-tabs v-model="tabActive">
<van-tab title="热门推荐" name="0">热门推荐</van-tab>
<van-tab title="我参与的" name="1">我参与的</van-tab>
<van-tab title="我发起的" name="2">我发起的</van-tab>
<van-tab title="热门推荐" name="0">
<hot-list />
</van-tab>
<van-tab title="我参与的" name="1">
<join-list />
</van-tab>
<van-tab title="我发起的" name="2">
<publish-list />
</van-tab>
</van-tabs>
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
v-if="list.length"
>
<card v-for="item in list" :data="item" :key="item.id"></card>
</van-list>
<div class="empty" v-else>{{ page.emptyText }}</div>
<div class="publish-button" @click="publishVisible = true"></div>
<van-popup v-model="publishVisible" position="bottom">
<div class="publish">
<ul>
<li @click="toCreatePage(0)">
<li @click="toCreatePage('10')">
<img src="~@/assets/img/icon_publish1.png" />发布活动
</li>
<li @click="toCreatePage(1)">
<li @click="toCreatePage('20')">
<img src="~@/assets/img/icon_publish2.png" />发布需求
</li>
</ul>
......@@ -32,9 +28,11 @@
</template>
<script>
import Card from '@/components/Card.vue'
import HotList from './HotList'
import JoinList from './JoinList'
import PublishList from './PublishList'
export default {
components: { Card },
components: { HotList, JoinList, PublishList },
metaInfo: {
title: '紫荆校友圈'
},
......@@ -70,10 +68,7 @@ export default {
this.getList()
},
toCreatePage(type) {
this.$router.push({
name: 'create',
query: Object.assign(this.$route.query, { publish_type: type })
})
this.$router.push({ name: 'create', query: { publish_type: type } })
}
}
}
......
<template>
<div class="detail"></div>
<div class="detail">
<!-- 封面 -->
<div class="detail-pic" v-if="detail.activity_image">
<img :src="detail.activity_image" />
</div>
<!-- 作者 -->
<div class="detail-user" v-if="detail.initiator">
<div class="detail-user__pic">
<img :src="detail.initiator.avatar" />
</div>
<div class="detail-user__content">
<p>{{ detail.initiator.nickname }}</p>
<p>{{ datetimeText }}</p>
</div>
<div class="detail-user__tool">
<span
class="join-button"
@click="$router.push({ name: 'join', params: { id: pid } })"
>报名</span
>
</div>
</div>
<!-- 标题 -->
<div class="detail-title">
<h1>{{ detail.activity_name }}</h1>
</div>
<!-- 内容 -->
<div class="detail-content">
<p>{{ detail.activity_contents }}</p>
</div>
<div class="detail-form">
<div class="detail-form__item" v-if="detail.activity_time">
<div class="detail-form__label">
<span class="detail-form-icon detail-form-icon__clock"></span>
时间:
</div>
<div class="detail-form__content">{{ detail.activity_time }}</div>
</div>
<div class="detail-form__item" v-if="detail.activity_address">
<div class="detail-form__label">
<span class="detail-form-icon detail-form-icon__address"></span>
地点:
</div>
<div class="detail-form__content">{{ detail.activity_address }}</div>
</div>
<div class="detail-form__item" v-if="detail.participator_limit">
<div class="detail-form__label">
<span class="detail-form-icon detail-form-icon__peoples"></span>
希望人数:
</div>
<div class="detail-form__content">
{{ detail.participator_limit }}
</div>
</div>
</div>
<!-- 评论 -->
<div class="detail-comments"></div>
</div>
</template>
<script>
import * as api from '@/api/index'
import { format } from 'timeago.js'
export default {
metaInfo: {
title: '文章内容'
title: '紫荆校友圈'
},
data() {
return {}
return {
detail: {}
}
},
computed: {
pid() {
return this.$route.params.id
},
datetimeText() {
return format(this.detail.created_time, 'zh_CN')
}
},
methods: {
getDetail() {
api.getActivity(this.pid).then(response => {
console.log(response)
})
}
},
beforeMount() {
this.getDetail()
}
}
</script>
<style lang="scss"></style>
<style lang="scss" scoped>
.detail {
padding: 0 20px;
}
.detail-pic {
margin-left: -20px;
margin-right: -20px;
margin-bottom: 20px;
img {
width: 100%;
}
}
.detail-user {
display: flex;
align-items: center;
margin-top: 20px;
}
.detail-user__pic {
width: 40px;
height: 40px;
background-color: #ccc;
border-radius: 50%;
overflow: hidden;
}
.detail-user__content {
flex: 1;
padding-left: 20px;
p {
font-size: 13px;
color: #999;
}
}
.join-button {
display: inline-block;
height: 30px;
padding: 0 20px;
line-height: 30px;
color: #fff;
background: linear-gradient(
180deg,
rgba(255, 155, 150, 1) 0%,
rgba(206, 62, 58, 1) 100%
);
border-radius: 20px;
cursor: pointer;
}
.detail-title {
margin-top: 20px;
h1 {
font-size: 18px;
color: #333;
line-height: 26px;
}
}
.detail-content {
margin-top: 20px;
p {
font-size: 15px;
color: #666;
line-height: 30px;
text-indent: 2em;
}
}
.detail-form__item {
display: flex;
align-items: flex-start;
margin-top: 20px;
line-height: 20px;
}
.detail-form__label {
display: flex;
}
.detail-form__content {
flex: 1;
overflow: hidden;
}
.detail-form-icon {
display: inline-block;
width: 20px;
height: 20px;
margin-right: 10px;
}
.detail-form-icon__clock {
background: url('~@/assets/img/icon_clock.png') no-repeat center;
background-size: contain;
}
.detail-form-icon__address {
background: url('~@/assets/img/icon_address.png') no-repeat center;
background-size: contain;
}
.detail-form-icon__peoples {
background: url('~@/assets/img/icon_peoples.png') no-repeat center;
background-size: contain;
}
</style>
<template>
<div class="main">
<v-form ref="form" :fields="fields" @submit="onSubmit"></v-form>
<div class="fixed-box">
<div class="fixed-inner">
<div class="fixed-button" @click="handleSubmit">提交</div>
</div>
</div>
</div>
</template>
<script>
import VForm from '@/components/Form'
import * as api from '@/api/index'
export default {
name: 'Join',
components: { VForm },
metaInfo: {
title: '活动报名'
},
data() {
return {
fields: [
{
name: 'personal_name',
label: '姓名',
required: true,
placeholder: '请输入姓名',
rules: [{ required: true, message: '请输入姓名' }]
},
{
type: 'tel',
name: 'mobile',
label: '手机号码',
required: true,
placeholder: '请输入手机号码',
rules: [{ required: true, message: '请输入手机号码' }]
},
{
name: 'contacts',
label: '联系方式',
required: true,
placeholder: '请输入手机号或微信号,仅发起人可见',
rules: [{ required: true, message: '请输入手机号或微信号' }]
},
{
fieldType: 'radio',
name: 'gender',
label: '真实性别',
required: true,
placeholder: '请选择性别',
rules: [{ required: true, message: '请选择性别' }],
values: [
{ name: '1', text: '男' },
{ name: '0', text: '女' }
]
},
{
name: 'class_name',
label: '班级名称',
required: true,
placeholder: '请输入班级名称',
rules: [{ required: true, message: '请输入班级名称' }]
},
{
type: 'textarea',
name: 'self_introduction',
label: '自我介绍(选填)',
placeholder:
'发起人会根据您的自我介绍来判断是否与 你同行,请认真诚恳的介绍下自己',
autosize: { maxHeight: 160, minHeight: 120 }
}
]
}
},
computed: {
pid() {
return this.$route.params.id
}
},
methods: {
handleSubmit() {
this.$refs.form.submit()
},
onSubmit(data) {
data.activity_id = this.pid
api.joinActivity(data).then(() => {
this.$dialog
.alert({
confirmButtonText: '确定',
message: '提交成功,可在“我参与的”里查看申请记录'
})
.then(() => {
this.$router.push({ name: 'index', query: { tab: '2' } })
})
})
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .van-radio-group--horizontal {
flex: 1;
.van-radio--horizontal {
flex: 1;
justify-content: center;
height: 40px;
border: 1px solid #999;
&[aria-checked='true'] {
background-color: #f38580;
border: 1px solid #f38580;
.van-radio__label {
color: #fff;
}
}
&:last-child {
margin-right: 0;
}
.van-radio__icon {
display: none;
}
}
}
</style>
<template>
<div class="list">
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
v-if="list.length"
>
<join-card v-for="item in list" :data="item" :key="item.id"></join-card>
</van-list>
<div class="empty" v-else>您还没有参与过活动哟</div>
</div>
</template>
<script>
import * as api from '@/api/index'
import JoinCard from '@/components/JoinCard'
export default {
components: { JoinCard },
data() {
return {
list: [],
loading: false,
finished: false,
page: { offset: 0, limit: 10 }
}
},
methods: {
getList() {
this.loading = true
api
.getJoinList(this.page)
.then(response => {
if (response.length) {
this.list = this.list.concat(response)
}
this.loading = false
this.finished = response.length < this.page.limit
})
.catch(() => {
this.loading = false
this.finished = true
})
},
onLoad() {
this.page.offset++
this.getList()
}
},
beforeMount() {
this.getList()
}
}
</script>
<template>
<div class="main"></div>
</template>
<script>
export default {
metaInfo: {
title: '查看已报名'
},
data() {
return {}
},
computed: {
pid() {
return this.$route.params.id
}
}
}
</script>
<style lang="scss" scoped></style>
......@@ -20,6 +20,7 @@
class="login-input"
placeholder="密码"
v-model="ruleForm.password"
@keyup.enter="onSubmit"
/>
</div>
<div class="login-form__item">
......@@ -101,6 +102,7 @@ export default {
// 登录成功
loginSuccess(response) {
if (response.ticket) {
localStorage.setItem('token', response.ticket)
if (this.redirectURI) {
window.location.href = this.redirectURI
} else {
......
<template>
<div class="list">
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
v-if="list.length"
>
<publish-card
v-for="item in list"
:data="item"
:key="item.id"
></publish-card>
</van-list>
<div class="empty" v-else>您还没有发起过活动哟</div>
</div>
</template>
<script>
import * as api from '@/api/index'
import PublishCard from '@/components/PublishCard'
export default {
components: { PublishCard },
data() {
return {
list: [],
loading: false,
finished: false,
page: { offset: 0, limit: 10 }
}
},
methods: {
getList() {
this.loading = true
api
.getPublishList(this.page)
.then(response => {
if (response.length) {
this.list = this.list.concat(response)
}
this.loading = false
this.finished = response.length < this.page.limit
})
.catch(() => {
this.loading = false
this.finished = true
})
},
onLoad() {
this.page.offset++
this.getList()
}
},
beforeMount() {
this.getList()
}
}
</script>
......@@ -4,6 +4,9 @@ module.exports = {
proxy: {
'/api/user_center': {
target: 'https://e-learning3.ezijing.com'
},
'/v1': {
target: 'https://alumni-api.ezijing.com'
}
}
}
......
......@@ -2709,6 +2709,11 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
dayjs@^1.8.23:
version "1.8.23"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.23.tgz#07b5a8e759c4d75ae07bdd0ad6977f851c01e510"
integrity sha512-NmYHMFONftoZbeOhVz6jfiXI4zSiPN6NoVWJgC0aZQfYVwzy/ZpESPHuCcI0B8BUMpSJQ08zenHDbofOLKq8hQ==
de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
......@@ -7655,6 +7660,11 @@ thunky@^1.0.2:
resolved "https://registry.npm.taobao.org/thunky/download/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
integrity sha1-Wrr3FKlAXbBQRzK7zNLO3Z75U30=
timeago.js@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/timeago.js/-/timeago.js-4.0.2.tgz#724e8c8833e3490676c7bb0a75f5daf20e558028"
integrity sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==
timers-browserify@^2.0.4:
version "2.0.11"
resolved "https://registry.npm.taobao.org/timers-browserify/download/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论