This commit is contained in:
caoqianming 2020-08-26 15:43:06 +08:00
parent 6c64f43613
commit 9ed24bb565
31 changed files with 260 additions and 9 deletions

View File

@ -94,6 +94,13 @@ export function unbindConsumer(id) {
})
}
export function claimConsumer(id) {
return request({
url: `/crm/consumer/${id}/claim/`,
method: 'put',
})
}
export function getConsumerRoleAll(query) {
return request({
url: '/crm/consumerrole/',

View File

@ -116,6 +116,12 @@ export const asyncRoutes = [
component: () => import('@/views/crm/consumer.vue'),
meta: { title: '学员列表', icon: '', perms: ['consumer_view'] }
},
{
path: 'claim',
name: 'Claim',
component: () => import('@/views/crm/claim.vue'),
meta: { title: '认领学员', icon: '', perms: ['consumer_view'] }
},
{
path: 'consumerrule',
name: 'ConsumerRule',

View File

@ -4,6 +4,7 @@ const getters = {
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
username: state=> state.user.username,
perms: state => state.user.perms,
permission_routes: state => state.permission.routes
}

View File

@ -0,0 +1,177 @@
<template>
<div class="app-container">
<div>
<el-input
v-model="listQuery.username"
placeholder="手机号"
style="width: 200px;"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">搜索</el-button>
<el-button
class="filter-item"
type="primary"
icon="el-icon-refresh-left"
@click="resetFilter"
>刷新重置</el-button>
</div>
<el-table
:data="consumerList"
style="width: 100%;margin-top:10px;"
border
fit
v-loading="listLoading"
highlight-current-row
max-height="600"
@sort-change="changeSort"
@selection-change="handleSelectionChange"
>
<el-table-column label="姓名">
<template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column label="手机号" sortable="custom" prop="username">
<template slot-scope="scope">{{ scope.row.username }}</template>
</el-table-column>
<el-table-column label="小程序OpenId" :show-overflow-tooltip="true">
<template slot-scope="scope">{{ scope.row.openid }}</template>
</el-table-column>
<el-table-column label="用户类型">
<template slot-scope="scope">{{ scope.row.role_name }}</template>
</el-table-column>
<el-table-column label="单位" sortable="custom" prop="company">
<template
slot-scope="scope"
v-if="scope.row.company_name != null"
>{{ scope.row.company_name }}</template>
</el-table-column>
<el-table-column label="缴费学科">
<template slot-scope="scope">
<el-tag v-for="item in scope.row.subjects_name" :key="item">{{ item }}</el-tag>
</template>
</el-table-column>
<el-table-column label="工作类别" sortable="custom" prop="workscope">
<template slot-scope="scope">
<el-tag v-if="scope.row.workscope_name">{{ scope.row.workscope_name }}</el-tag>
</template>
</el-table-column>
<el-table-column label="创建信息" sortable="custom" prop="create_time">
<template slot-scope="scope">
<span v-if="scope.row.create_admin_">{{ scope.row.create_admin_.username }}/</span>
<span>{{ scope.row.create_time.substring(0,10) }}</span>
</template>
</el-table-column>
<el-table-column align="left" label="操作" fixed="right" width="260">
<template slot-scope="scope">
<el-button-group>
<el-button
type="primary"
size="small"
@click="handleClaim(scope)"
:disabled="!checkPermission(['consumer_claim'])"
>认领</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="listQuery.page"
:limit.sync="listQuery.limit"
@pagination="getList"
/>
</div>
</template>
<script>
import {
getConsumerList,
claimConsumer
} from "@/api/crm";
import { genTree, deepClone } from "@/utils";
import checkPermission from "@/utils/permission";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const listQuery = {
page: 1,
limit: 20,
adminoff: true,
};
export default {
components: { Pagination },
watch: {
},
data() {
return {
consumerList: [],
total: 0,
listLoading: true,
listQuery: {
page: 1,
limit: 20,
adminoff: true,
},
selects: [],
};
},
computed: {},
watch: {
},
created() {
this.getList();
},
methods: {
changeSort(val) {
if (val.order == "ascending") {
this.listQuery.ordering = val.prop;
} else {
this.listQuery.ordering = "-" + val.prop;
}
this.getList();
},
handleSelectionChange(val) {
let selects = [];
for (var i = 0; i < val.length; i++) {
selects.push(val[i].id);
}
this.selects = selects;
},
checkPermission,
getList() {
this.listLoading = true;
getConsumerList(this.listQuery).then((response) => {
this.consumerList = response.data.results;
this.total = response.data.count;
this.listLoading = false;
});
},
resetFilter() {
this.listQuery = {
page: 1,
limit: 20,
adminoff: true,
};
this.getList();
},
handleFilter() {
this.listQuery.page = 1;
this.getList();
},
handleClaim(scope) {
this.$confirm("确定认领该用户吗?", "提示", {
}).then(()=>{
claimConsumer(scope.row.id).then(res=>{
this.$message.success('认领成功')
})
})
},
},
};
</script>

View File

@ -182,11 +182,11 @@
</el-table-column>
<el-table-column label="创建信息" sortable="custom" prop="create_time" v-if="showCreate">
<template slot-scope="scope">
<span>{{ scope.row.create_admin_.username }}/</span>
<span v-if="scope.row.create_admin_">{{ scope.row.create_admin_.username }}/</span>
<span>{{ scope.row.create_time.substring(0,10) }}</span>
</template>
</el-table-column>
<el-table-column align="left" label="操作" fixed="right" width="200">
<el-table-column align="left" label="操作" fixed="right" width="260">
<template slot-scope="scope">
<el-button-group>
<el-button

View File

@ -69,9 +69,9 @@ App({
globalData: {
userInfo: {},
userinfo: {}, // 服务器传回的消费者信息
//host: 'https://apitest.ahctc.cn',
host: 'https://apitest.ahctc.cn',
mediahost: 'https://apitest.ahctc.cn',
host: 'http://127.0.0.1:8000',
//host: 'http://127.0.0.1:8000',
//mediahost: 'http://127.0.0.1:8000',
token : '',
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
test_mini/images/data1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 902 B

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
test_mini/images/home1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 902 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
test_mini/images/me1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 808 B

BIN
test_mini/images/news1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
test_mini/images/play1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
test_mini/images/playc1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -68,9 +68,20 @@ Page({
getDetail: function (id) {
var that = this
wx.showLoading({
title: '加载中',
mask:true
})
api.request(`/cms/article/${id}/`,'GET').then(res => {
// res.data.content = res.data.content.replace(/"media/g, '"'+getApp().globalData.mediahost + '/media').replace(/\<img/gi, '<img style="max-width:100%;height:auto" ')
that.setData(res.data)
wx.hideLoading({
complete: (res) => {},
})
}).catch(res=>{
wx.hideLoading({
complete: (res) => {},
})
})
},

View File

@ -1 +1,7 @@
/* pages/article/detail.wxss */
/* pages/article/detail.wxss */
.weui-article {
padding: 0px 12px;
}
.page__title {
font-size: 18px;
}

View File

@ -14,7 +14,7 @@
</view>
</view>
<view class="weui-panel__ft weui-cell__ft_in-access">
<view class="weui-media-box__desc">查看详情</view>
</view>
</navigator>
</block>

View File

@ -23,7 +23,7 @@
"disablePlugins": [],
"outputPath": ""
},
"useCompilerModule": false,
"useCompilerModule": true,
"userConfirmedUseCompilerModuleSwitch": false,
"compileHotReLoad": false,
"useIsolateContext": true

View File

@ -8,4 +8,4 @@ class ConsumerFilter(filters.FilterSet):
class Meta:
model = Consumer
fields = ['company', 'role', 'min_create', 'max_create', 'create_admin']
fields = ['company', 'role', 'min_create', 'max_create', 'create_admin', 'username']

View File

@ -0,0 +1,21 @@
# Generated by Django 3.0.4 on 2020-08-26 06:44
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('crm', '0022_consumer_exceed_date'),
]
operations = [
migrations.AlterField(
model_name='consumer',
name='create_admin',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
]

View File

@ -72,7 +72,7 @@ class Consumer(CommonModel):
ID_number = models.CharField('身份证号', max_length=100, null=True, blank=True)
realname = models.CharField('真实姓名', max_length=100, null=True, blank=True)
create_admin = models.ForeignKey(UserProfile, default=1, on_delete=models.DO_NOTHING)
create_admin = models.ForeignKey(UserProfile, on_delete=models.SET_NULL, null=True, blank=True)
exceed_date = models.DateField('账号过期', null=True, blank=True)

View File

@ -149,6 +149,8 @@ class ConsumerViewSet(ModelViewSet):
def get_queryset(self):
queryset = self.queryset
queryset = self.get_serializer_class().setup_eager_loading(queryset)
if self.request.query_params.get('adminoff', None):
return queryset.filter(create_admin=None)
if not self.request.user.is_superuser:
queryset = queryset.filter(create_admin = self.request.user)
return queryset
@ -277,6 +279,7 @@ class ConsumerViewSet(ModelViewSet):
request.user.realname = request.data['realname']
request.user.save()
return Response(status=status.HTTP_200_OK)
@action(methods=['get'], detail=False,
url_path='candidate', url_name='consumer_candidate', perms_map=[{'*':'*'}])
@ -419,6 +422,22 @@ class ConsumerViewSet(ModelViewSet):
def correctexceed(self, request):
Consumer.objects.exclude(exceed_date=None).update(exceed_date = datetime(2020,12,31))
return Response(status=status.HTTP_200_OK)
@action(methods=['get'], detail=False,
url_path='correctadmin', url_name='correct_admin', perms_map=[{'*':'correct_admin'}])
def correctadmin(self, request):
Consumer.objects.filter(name='').update(create_admin=None)
return Response(status=status.HTTP_200_OK)
@action(methods=['put'], detail=True, url_name='consumer_claim', perms_map=[{'*':'consumer_claim'}])
def claim(self, request, *args, **kwargs):
obj = self.get_object()
if obj.role.username and obj.create_admin is None:
obj.create_admin = request.user
obj.save()
return Response(status=status.HTTP_200_OK)
else:
return Response({"error":"认领失败!"})
class ConsumerMPLoginView(APIView):
"""

View File

@ -302,9 +302,12 @@ class ExamTestViewSet(ModelViewSet):
def export(self, request):
queryset = self.filter_queryset(self.get_queryset())
queryset = ExamTestListSerializer.setup_eager_loading(queryset) # 性能优化
if queryset.count()>1000:
return Response({'error':'数据量超过1000,请筛选后导出!'})
serializer = ExamTestListSerializer(instance=queryset, many=True)
path = export_test(serializer.data)
return Response({'path': path})
class PaperViewSet(ModelViewSet):
"""
押题卷增删改查