于宏哲PHP 10 months ago
parent
commit
cf3332e226
  1. 58
      admin/src/app/api/contract_sign.ts
  2. 17
      admin/src/app/lang/zh-cn/contract_sign.contract_sign.json
  3. 184
      admin/src/app/views/contract_sign/components/contract-sign-edit.vue
  4. 235
      admin/src/app/views/contract_sign/contract_sign.vue
  5. 97
      niucloud/app/adminapi/controller/contract_sign/ContractSign.php
  6. 42
      niucloud/app/adminapi/route/contract_sign.php
  7. 199
      niucloud/app/api/controller/apiController/Statistics.php
  8. 118
      niucloud/app/model/contract_sign/ContractSign.php
  9. 111
      niucloud/app/service/admin/contract_sign/ContractSignService.php
  10. 37
      niucloud/app/validate/contract_sign/ContractSign.php

58
admin/src/app/api/contract_sign.ts

@ -0,0 +1,58 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- contract_sign
/**
*
* @param params
* @returns
*/
export function getContractSignList(params: Record<string, any>) {
return request.get(`contract_sign/contract_sign`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getContractSignInfo(id: number) {
return request.get(`contract_sign/contract_sign/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addContractSign(params: Record<string, any>) {
return request.post('contract_sign/contract_sign', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editContractSign(params: Record<string, any>) {
return request.put(`contract_sign/contract_sign/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteContractSign(id: number) {
return request.delete(`contract_sign/contract_sign/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithContractList(params: Record<string,any>){
return request.get('contract_sign/contract_all', {params})
}export function getWithPersonnelList(params: Record<string,any>){
return request.get('contract_sign/personnel_all', {params})
}
// USER_CODE_END -- contract_sign

17
admin/src/app/lang/zh-cn/contract_sign.contract_sign.json

@ -0,0 +1,17 @@
{
"contractId":"合同",
"contractIdPlaceholder":"请输入合同",
"personnelId":"下发人员",
"personnelIdPlaceholder":"请输入下发人员",
"status":"签署状态",
"statusPlaceholder":"请输入签署状态",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"signTime":"签署时间",
"signTimePlaceholder":"请输入签署时间",
"addContractSign":"添加合同关系",
"updateContractSign":"编辑合同关系",
"contractSignDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

184
admin/src/app/views/contract_sign/components/contract-sign-edit.vue

@ -0,0 +1,184 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateContractSign') : t('addContractSign')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('contractId')" prop="contract_id">
<el-select class="input-width" v-model="formData.contract_id" clearable :placeholder="t('contractIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in contractIdList"
:key="index"
:label="item['contract_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('personnelId')" prop="personnel_id">
<el-select class="input-width" v-model="formData.personnel_id" clearable :placeholder="t('personnelIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in personnelIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addContractSign, editContractSign, getContractSignInfo, getWithContractList, getWithPersonnelList } from '@/app/api/contract_sign'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
contract_id: '',
personnel_id: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
contract_id: [
{ required: true, message: t('contractIdPlaceholder'), trigger: 'blur' },
]
,
personnel_id: [
{ required: true, message: t('personnelIdPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editContractSign : addContractSign
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
let data = formData
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
}).catch(err => {
loading.value = false
})
}
})
}
//
let statusList = ref([])
const statusDictList = async () => {
statusList.value = await (await useDictionary('contract_status')).data.dictionary
}
statusDictList();
watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
const contractIdList = ref([] as any[])
const setContractIdList = async () => {
contractIdList.value = await (await getWithContractList({})).data
}
setContractIdList()
const personnelIdList = ref([] as any[])
const setPersonnelIdList = async () => {
personnelIdList.value = await (await getWithPersonnelList({})).data
}
setPersonnelIdList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getContractSignInfo(row.id)).data
if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
loading.value = false
}
//
const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile')))
} else {
callback()
}
}
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
}
//
const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail')))
} else {
callback()
}
}
//
const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber')))
} else {
callback()
}
}
defineExpose({
showDialog,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label{
height: auto !important;
}
</style>

235
admin/src/app/views/contract_sign/contract_sign.vue

@ -0,0 +1,235 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addContractSign') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="contractSignTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('status')" prop="status">
<el-select class="w-[280px]" v-model="contractSignTable.searchParam.status" clearable :placeholder="t('statusPlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-date-picker v-model="contractSignTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item :label="t('signTime')" prop="sign_time">
<el-date-picker v-model="contractSignTable.searchParam.sign_time" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadContractSignList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table :data="contractSignTable.data" size="large" v-loading="contractSignTable.loading">
<template #empty>
<span>{{ !contractSignTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="contract_id_name" :label="t('contractId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="personnel_id_name" :label="t('personnelId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in statusList">
<div v-if="item.value == row.status">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="预览" min-width="120" >
<template #default="{ row }">
<template v-if="!row.sign_file">
未签署
</template>
<template v-else-if="row.sign_file">
<el-button type="success" text @click="openFile(row.sign_file)">打开文件</el-button>
</template>
</template>
</el-table-column>
<el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="sign_time" :label="t('signTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="contractSignTable.page" v-model:page-size="contractSignTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="contractSignTable.total"
@size-change="loadContractSignList()" @current-change="loadContractSignList" />
</div>
</div>
<edit ref="editContractSignDialog" @complete="loadContractSignList" />
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import { getContractSignList, deleteContractSign, getWithContractList, getWithPersonnelList } from '@/app/api/contract_sign'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/contract_sign/components/contract-sign-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let contractSignTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"status":"",
"created_at":[],
"sign_time":[]
}
})
const openFile = (url: string) => {
window.open(`${import.meta.env.VITE_IMG_DOMAIN}/${url}`, '_blank');
};
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
const statusList = ref([] as any[])
const statusDictList = async () => {
statusList.value = await (await useDictionary('contract_status')).data.dictionary
}
statusDictList();
/**
* 获取合同关系列表
*/
const loadContractSignList = (page: number = 1) => {
contractSignTable.loading = true
contractSignTable.page = page
getContractSignList({
page: contractSignTable.page,
limit: contractSignTable.limit,
...contractSignTable.searchParam
}).then(res => {
contractSignTable.loading = false
contractSignTable.data = res.data.data
contractSignTable.total = res.data.total
}).catch(() => {
contractSignTable.loading = false
})
}
loadContractSignList()
const editContractSignDialog: Record<string, any> | null = ref(null)
/**
* 添加合同关系
*/
const addEvent = () => {
editContractSignDialog.value.setFormData()
editContractSignDialog.value.showDialog = true
}
/**
* 编辑合同关系
* @param data
*/
const editEvent = (data: any) => {
editContractSignDialog.value.setFormData(data)
editContractSignDialog.value.showDialog = true
}
/**
* 删除合同关系
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('contractSignDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteContractSign(id).then(() => {
loadContractSignList()
}).catch(() => {
})
})
}
const contractIdList = ref([])
const setContractIdList = async () => {
contractIdList.value = await (await getWithContractList({})).data
}
setContractIdList()
const personnelIdList = ref([])
const setPersonnelIdList = async () => {
personnelIdList.value = await (await getWithPersonnelList({})).data
}
setPersonnelIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadContractSignList()
}
</script>
<style lang="scss" scoped>
/* 多行超出隐藏 */
.multi-hidden {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>

97
niucloud/app/adminapi/controller/contract_sign/ContractSign.php

@ -0,0 +1,97 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\adminapi\controller\contract_sign;
use core\base\BaseAdminController;
use app\service\admin\contract_sign\ContractSignService;
/**
* 合同关系控制器
* Class ContractSign
* @package app\adminapi\controller\contract_sign
*/
class ContractSign extends BaseAdminController
{
/**
* 获取合同关系列表
* @return \think\Response
*/
public function lists(){
$data = $this->request->params([
["status",""],
["created_at",["",""]],
["sign_time",["",""]]
]);
return success((new ContractSignService())->getPage($data));
}
/**
* 合同关系详情
* @param int $id
* @return \think\Response
*/
public function info(int $id){
return success((new ContractSignService())->getInfo($id));
}
/**
* 添加合同关系
* @return \think\Response
*/
public function add(){
$data = $this->request->params([
["contract_id",0],
["personnel_id",0],
]);
$this->validate($data, 'app\validate\contract_sign\ContractSign.add');
$id = (new ContractSignService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
}
/**
* 合同关系编辑
* @param $id 合同关系id
* @return \think\Response
*/
public function edit(int $id){
$data = $this->request->params([
["contract_id",0],
["personnel_id",0],
]);
$this->validate($data, 'app\validate\contract_sign\ContractSign.edit');
(new ContractSignService())->edit($id, $data);
return success('EDIT_SUCCESS');
}
/**
* 合同关系删除
* @param $id 合同关系id
* @return \think\Response
*/
public function del(int $id){
(new ContractSignService())->del($id);
return success('DELETE_SUCCESS');
}
public function getContractAll(){
return success(( new ContractSignService())->getContractAll());
}
public function getPersonnelAll(){
return success(( new ContractSignService())->getPersonnelAll());
}
}

42
niucloud/app/adminapi/route/contract_sign.php

@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- contract_sign
Route::group('contract_sign', function () {
//合同关系列表
Route::get('contract_sign', 'contract_sign.ContractSign/lists');
//合同关系详情
Route::get('contract_sign/:id', 'contract_sign.ContractSign/info');
//添加合同关系
Route::post('contract_sign', 'contract_sign.ContractSign/add');
//编辑合同关系
Route::put('contract_sign/:id', 'contract_sign.ContractSign/edit');
//删除合同关系
Route::delete('contract_sign/:id', 'contract_sign.ContractSign/del');
Route::get('contract_all','contract_sign.ContractSign/getContractAll');
Route::get('personnel_all','contract_sign.ContractSign/getPersonnelAll');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,
AdminLog::class
]);
// USER_CODE_END -- contract_sign

199
niucloud/app/api/controller/apiController/Statistics.php

@ -11,9 +11,17 @@
namespace app\api\controller\apiController; namespace app\api\controller\apiController;
use app\model\market_performance\MarketPerformance;
use app\model\order_table\OrderTable;
use app\Request; use app\Request;
use app\service\api\apiService\CommonService; use app\service\api\apiService\CommonService;
use core\base\BaseApiService; use core\base\BaseApiService;
use app\model\customer_resources\CustomerResources;
use think\facade\Db;
use app\model\resource_sharing\ResourceSharing;
use app\model\six_speed\SixSpeed;
/** /**
* 统计控制器相关接口 * 统计控制器相关接口
@ -28,6 +36,12 @@ class Statistics extends BaseApiService
*/ */
public function marketHome(Request $request) public function marketHome(Request $request)
{ {
$customerResources = new CustomerResources();
$resourceSharing = new ResourceSharing();
$communication_records = new CommunicationRecords();
$market_performance = new MarketPerformance();
$six_speed = new SixSpeed();
$order = new OrderTable();
$personnel_id = $request->param('personnel_id','');//员工表id $personnel_id = $request->param('personnel_id','');//员工表id
$role_key_arr = $request->param('role_key_arr','');//array 角色key $role_key_arr = $request->param('role_key_arr','');//array 角色key
//字符转数组 //字符转数组
@ -42,63 +56,184 @@ class Statistics extends BaseApiService
// $role_key_arr = ['sale'];//@todo 调试使用 // $role_key_arr = ['sale'];//@todo 调试使用
if(in_array('market',$role_key_arr) || in_array('market_manager',$role_key_arr)){ if(in_array('market',$role_key_arr) || in_array('market_manager',$role_key_arr)){
$yesterdayStart = date('Y-m-d', strtotime('-1 day'));
$lastMonthStart = date('Y-m', strtotime('-1 month'));
$customer_list = $customerResources->where(['consultant' => $personnel_id])->select();
$newTotal = 0;
$assignedSales = 0;
$yesterdayNew = 0;
$todayNew = 0;
$yjsr = 0;
$wfpsl = 0;
$bytc = 0;
$gdsl = 0;
$lastNewTotal = 0;
$lastAssignedSales = 0;
foreach($customer_list as $item){
if($item['create_year_month'] == date("Y-m")){
$newTotal++;
if($resourceSharing->where(['resource_id' => $item['id']])->find()){
$assignedSales++;
}
}
if($item['create_year_month'] == $lastMonthStart){
$lastNewTotal++;
if($resourceSharing->where(['resource_id' => $item['id']])->find()){
$lastAssignedSales++;
}
}
if($item['create_date'] == $yesterdayStart){
$yesterdayNew++;
}
if($item['create_date'] == date("Y-m-d")){
$todayNew++;
}
if(!$resourceSharing->where(['resource_id' => $item['id']])->find()){
$wfpsl++;
}
if($order->where(['resource_id' => $item['id'],'order_type' => '1'])->find()){
if($six_speed->where(['resource_id' => $item['id'],'is_closed' => 1])->find()){
$gdsl++;
}
}
}
$yjsr = $market_performance->where([
'performance_date' => date('Y-m-d'),
'personnel_id' => $personnel_id
])->Sum('performance_amount');
$bytc = $market_performance
->where(['personnel_id' => $personnel_id])
->whereTime('performance_date', 'month')
->sum('performance_amount');
//市场人员统计数据(地推拉人头的) //市场人员统计数据(地推拉人头的)
$data = [ $data = [
'date_range'=>$dateRange,//拼接日期范围字符串 'date_range'=>$dateRange,//拼接日期范围字符串
'role_type'=>'market_type',//角色类型|market_type=市场,sale_type=销售 'role_type'=>'market_type',//角色类型|market_type=市场,sale_type=销售
//本月 //本月
'month' => [ 'month' => [
'new_total' => ($newTotal = rand(100, 500)),//拉新总人数 'new_total' => $newTotal,//拉新总人数
'new_total_rate' => min(100, round($newTotal / 1000 * 100, 2)),//拉新总人数比例(不超过100%) 'new_total_rate' => min(100, round($newTotal / 1000 * 100, 2)),//拉新总人数比例(不超过100%)
'assigned_sales' => ($assignedSales = rand(50, 300)),//已分配给销售的人数 'assigned_sales' => $assignedSales,//已分配给销售的人数
'assigned_sales_rate' => min(100, round($assignedSales / $newTotal * 100, 2)),//已分配给销售的人数比例(不超过100%) 'assigned_sales_rate' => $newTotal ? min(100, round($assignedSales / $newTotal * 100, 2)) : 0,//已分配给销售的人数比例(不超过100%)
'yesterday_new' => ($yesterdayNew = rand(5, 50)),//昨日拉新 'yesterday_new' => $yesterdayNew,//昨日拉新
'yesterday_new_rate' => min(100, round($yesterdayNew / $newTotal * 100, 2)),//昨日拉新比例(不超过100%) 'yesterday_new_rate' => $newTotal ? min(100, round($yesterdayNew / $newTotal * 100, 2)) : 0,//昨日拉新比例(不超过100%)
'today_new' => ($todayNew = rand(1, 20)),//今日拉新 'today_new' => $todayNew,//今日拉新
'today_new_rate' => min(100, round($todayNew / $newTotal * 100, 2)),//今日拉新比例(不超过100%) 'today_new_rate' => $newTotal ? min(100, round($todayNew / $newTotal * 100, 2)) : 0,//今日拉新比例(不超过100%)
], ],
//上月 //上月
'last_month' => [ 'last_month' => [
'new_total' => ($lastNewTotal = rand(80, 400)),//拉新总人数 'new_total' => $lastNewTotal,//拉新总人数
'new_total_rate' => min(100, round($lastNewTotal / 800 * 100, 2)),//拉新总人数比例(不超过100%) 'new_total_rate' => min(100, round($lastNewTotal / 800 * 100, 2)),//拉新总人数比例(不超过100%)
'assigned_sales' => ($lastAssignedSales = rand(40, 250)),//已分配给销售的人数 'assigned_sales' => $lastAssignedSales,//已分配给销售的人数
'assigned_sales_rate' => min(100, round($lastAssignedSales / $lastNewTotal * 100, 2)),//已分配给销售的人数比例(不超过100%) 'assigned_sales_rate' => $lastNewTotal ? min(100, round($lastAssignedSales / $lastNewTotal * 100, 2)) : 0,//已分配给销售的人数比例(不超过100%)
'yesterday_new' => ($lastYesterdayNew = rand(3, 40)),//昨日拉新人数 'yesterday_new' =>$yesterdayNew,//昨日拉新人数
'yesterday_new_rate' => min(100, round($lastYesterdayNew / $lastNewTotal * 100, 2)),//昨日拉新人数比例(不超过100%) 'yesterday_new_rate' => $lastNewTotal ? min(100, round($yesterdayNew / $lastNewTotal * 100, 2)) : 0,//昨日拉新人数比例(不超过100%)
'today_new' => ($lastTodayNew = rand(1, 15)),//今日拉新人数 'today_new' => $todayNew,//今日拉新人数
'today_new_rate' => min(100, round($lastTodayNew / $lastNewTotal * 100, 2)),//今日拉新人数比例(不超过100%) 'today_new_rate' => $lastNewTotal ? min(100, round($todayNew / $lastNewTotal * 100, 2)) : 0,//今日拉新人数比例(不超过100%)
'xzzy' => $todayNew,
'yjsr' => $yjsr,
'wfpsl' => $wfpsl,
'bytc' => $bytc,
'gdsl' => $gdsl
] ]
]; ];
}elseif(in_array('sale',$role_key_arr) || in_array('sale_manager',$role_key_arr)){ }elseif(in_array('sale',$role_key_arr) || in_array('sale_manager',$role_key_arr)){
$startTime = date('Y-m-01 00:00:00');
$endTime = date('Y-m-t 23:59:59');
$last_monthstartTime = date('Y-m-01 00:00:00', strtotime('first day of last month'));
$last_monthendTime = date('Y-m-t 23:59:59', strtotime('last day of last month'));
$resource_list = $resourceSharing->where(['shared_by' => $personnel_id])->select();
$assigned = 0;
$contacted = 0;
$unconverted = 0;
$renewal = 0;
$closed = 0;
$lastAssigned = 0;
$lastContacted = 0;
$lastUnconverted = 0;
$lastClosed = 0;
foreach($resource_list as $item){
$sharedAt = strtotime($item['shared_at']);
if ($sharedAt >= strtotime($startTime) && $sharedAt <= strtotime($endTime)) {
$assigned++;
$records = $communication_records->where(['resource_id' => $item['resource_id']])->order("id desc")->find();
if($records){
$contacted++;
if($records['communication_result'] !== 'success'){
$unconverted++;
}
}
if($six_speed->where(['resource_id' => $item['resource_id'],'is_closed' => 1])->find()){
$closed++;
}
}
if ($sharedAt >= strtotime($last_monthstartTime) && $sharedAt <= strtotime($last_monthendTime)) {
$lastAssigned++;
$records = $communication_records->where(['resource_id' => $item['resource_id']])->order("id desc")->find();
if($records){
$lastContacted++;
if($records['communication_result'] !== 'success'){
$lastUnconverted++;
}
}
if($six_speed->where(['resource_id' => $item['resource_id'],'is_closed' => 1])->find()){
$lastClosed++;
}
}
}
//销售人员统计数据(买课的) //销售人员统计数据(买课的)
$data = [ $data = [
'date_range'=>$dateRange,//拼接日期范围字符串 'date_range'=>$dateRange,//拼接日期范围字符串
'role_type'=>'sale_type',//角色类型|market_type=市场,sale_type=销售 infoData.month 'role_type'=>'sale_type',//角色类型|market_type=市场,sale_type=销售 infoData.month
//本月 //本月
'month' => [ 'month' => [
'assigned_clients' => ($assigned = rand(50, 300)),//分配给我的客户人数 'assigned_clients' => $assigned,//分配给我的客户人数
'contacted_clients' => ($contacted = rand(20, 150)),//已沟通的客户人数 'contacted_clients' => $contacted,//已沟通的客户人数
'contact_rate' => min(100, round($contacted / $assigned * 100, 2)),//沟通率(不超过100%) 'contact_rate' => $assigned ? min(100, round($contacted / $assigned * 100, 2)) : 0,//沟通率(不超过100%)
'unconverted_clients' => ($unconverted = rand(10, 50)),//已沟通但没成交的客户人数 'unconverted_clients' => $unconverted,//已沟通但没成交的客户人数
'unconverted_rate' => min(100, round($unconverted / $contacted * 100, 2)),//未成交率(不超过100%) 'unconverted_rate' => $contacted ? min(100, round($unconverted / $contacted * 100, 2)) : 0,//未成交率(不超过100%)
'renewal_clients' => ($renewal = rand(5, 30)),//待续费的客户人数 'renewal_clients' => ($renewal = rand(5, 30)),//待续费的客户人数
'renewal_rate' => min(100, round($renewal / $assigned * 100, 2)),//待续费率(不超过100%) 'renewal_rate' => $assigned ? min(100, round($renewal / $assigned * 100, 2)) : 0,//待续费率(不超过100%)
'closed_clients' => ($closed = rand(1, 20)),//已关单的客户人数 'closed_clients' => $closed,//已关单的客户人数
'closed_rate' => min(100, round($closed / $contacted * 100, 2)),//关单率(不超过100%) 'closed_rate' => $contacted ? min(100, round($closed / $contacted * 100, 2)) : 0,//关单率(不超过100%)
'conversion_rate' => min(100, round($closed / $assigned * 100, 2)),//整体转化率(不超过100%) 'conversion_rate' => $assigned ? min(100, round($closed / $assigned * 100, 2)) : 0,//整体转化率(不超过100%)
], ],
//上月 //上月
'last_month' => [ 'last_month' => [
'assigned_clients' => ($lastAssigned = rand(40, 250)),//分配给我的客户人数 'assigned_clients' => $lastAssigned,//分配给我的客户人数
'contacted_clients' => ($lastContacted = rand(15, 120)),//已沟通的客户人数 'contacted_clients' => $lastContacted,//已沟通的客户人数
'contact_rate' => min(100, round($lastContacted / $lastAssigned * 100, 2)),//沟通率(不超过100%) 'contact_rate' => $lastAssigned ? min(100, round($lastContacted / $lastAssigned * 100, 2)) : 0,//沟通率(不超过100%)
'unconverted_clients' => ($lastUnconverted = rand(8, 40)),//已沟通但没成交的客户人数 'unconverted_clients' => $lastUnconverted,//已沟通但没成交的客户人数
'unconverted_rate' => min(100, round($lastUnconverted / $lastContacted * 100, 2)),//未成交率(不超过100%) 'unconverted_rate' => $lastContacted ? min(100, round($lastUnconverted / $lastContacted * 100, 2)) : 0,//未成交率(不超过100%)
'renewal_clients' => ($lastRenewal = rand(3, 25)),//待续费的客户人数 'renewal_clients' => ($lastRenewal = rand(3, 25)),//待续费的客户人数
'renewal_rate' => min(100, round($lastRenewal / $lastAssigned * 100, 2)),//待续费率(不超过100%) 'renewal_rate' => $lastAssigned ? min(100, round($lastRenewal / $lastAssigned * 100, 2)) : 0,//待续费率(不超过100%)
'closed_clients' => ($lastClosed = rand(1, 15)),//已关单的客户人数 'closed_clients' => $lastClosed,//已关单的客户人数
'closed_rate' => min(100, round($lastClosed / $lastContacted * 100, 2)),//关单率(不超过100%) 'closed_rate' => $lastContacted ? min(100, round($lastClosed / $lastContacted * 100, 2)) : 0,//关单率(不超过100%)
'conversion_rate' => min(100, round($lastClosed / $lastAssigned * 100, 2)),//整体转化率(不超过100%) 'conversion_rate' => $lastAssigned ? min(100, round($lastClosed / $lastAssigned * 100, 2)) : 0,//整体转化率(不超过100%)
] ]
]; ];
}else{ }else{

118
niucloud/app/model/contract_sign/ContractSign.php

@ -0,0 +1,118 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\contract_sign;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\contract\Contract;
use app\model\personnel\Personnel;
/**
* 合同关系模型
* Class ContractSign
* @package app\model\contract_sign
*/
class ContractSign extends BaseModel
{
use SoftDelete;
/**
* 数据表主键
* @var string
*/
protected $pk = 'id';
/**
* 模型名称
* @var string
*/
protected $name = 'contract_sign';
/**
* 定义软删除标记字段.
* @var string
*/
protected $deleteTime = 'deleted_at';
/**
* 定义软删除字段的默认值.
* @var int
*/
protected $defaultSoftDelete = 0;
/**
* 搜索器:合同关系签署状态
* @param $value
* @param $data
*/
public function searchStatusAttr($query, $value, $data)
{
if ($value) {
$query->where("status", $value);
}
}
/**
* 搜索器:合同关系创建时间
* @param $value
* @param $data
*/
public function searchCreatedAtAttr($query, $value, $data)
{
$start = empty($value[0]) ? 0 : strtotime($value[0]);
$end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
}
}
/**
* 搜索器:合同关系签署时间
* @param $value
* @param $data
*/
public function searchSignTimeAttr($query, $value, $data)
{
$start = empty($value[0]) ? 0 : strtotime($value[0]);
$end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["sign_time", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["sign_time", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["sign_time", "<=", $end]]);
}
}
public function contract(){
return $this->hasOne(Contract::class, 'id', 'contract_id')->joinType('left')->withField('contract_name,id')->bind(['contract_id_name'=>'contract_name']);
}
public function personnel(){
return $this->hasOne(Personnel::class, 'id', 'personnel_id')->joinType('left')->withField('name,id')->bind(['personnel_id_name'=>'name']);
}
}

111
niucloud/app/service/admin/contract_sign/ContractSignService.php

@ -0,0 +1,111 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\admin\contract_sign;
use app\model\contract_sign\ContractSign;
use app\model\contract\Contract;
use app\model\personnel\Personnel;
use core\base\BaseAdminService;
/**
* 合同关系服务层
* Class ContractSignService
* @package app\service\admin\contract_sign
*/
class ContractSignService extends BaseAdminService
{
public function __construct()
{
parent::__construct();
$this->model = new ContractSign();
}
/**
* 获取合同关系列表
* @param array $where
* @return array
*/
public function getPage(array $where = [])
{
$field = 'id,contract_id,personnel_id,sign_file,status,created_at,sign_time,updated_at,deleted_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["status","created_at","sign_time"], $where)->with(['contract','personnel'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
/**
* 获取合同关系信息
* @param int $id
* @return array
*/
public function getInfo(int $id)
{
$field = 'id,contract_id,personnel_id,sign_file,status,created_at,sign_time,updated_at,deleted_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['contract','personnel'])->findOrEmpty()->toArray();
return $info;
}
/**
* 添加合同关系
* @param array $data
* @return mixed
*/
public function add(array $data)
{
$res = $this->model->create($data);
return $res->id;
}
/**
* 合同关系编辑
* @param int $id
* @param array $data
* @return bool
*/
public function edit(int $id, array $data)
{
$this->model->where([['id', '=', $id]])->update($data);
return true;
}
/**
* 删除合同关系
* @param int $id
* @return bool
*/
public function del(int $id)
{
$model = $this->model->where([['id', '=', $id]])->find();
$res = $model->delete();
return $res;
}
public function getContractAll(){
$contractModel = new Contract();
return $contractModel->select()->toArray();
}
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
}

37
niucloud/app/validate/contract_sign/ContractSign.php

@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\validate\contract_sign;
use core\base\BaseValidate;
/**
* 合同关系验证器
* Class ContractSign
* @package addon\app\validate\contract_sign
*/
class ContractSign extends BaseValidate
{
protected $rule = [
'contract_id' => 'require',
'personnel_id' => 'require',
];
protected $message = [
'contract_id.require' => ['common_validate.require', ['contract_id']],
'personnel_id.require' => ['common_validate.require', ['personnel_id']],
];
protected $scene = [
"add" => ['contract_id', 'personnel_id'],
"edit" => ['contract_id', 'personnel_id']
];
}
Loading…
Cancel
Save