完善功能

main
yanzai 2 years ago
parent c931f0bdb1
commit bc5eccbe77

Binary file not shown.

@ -9,10 +9,13 @@ use App\Services\Admin\UserService;
class UserController extends Controller
{
public function GetInfoList(){
$status =request('status');
$cname =request('cname');
$departmentid =request('departmentid');
$page =request('page');
$pagesize =request('pageSize');
$s=app()->make(UserService::class);
return $s->GetInfoList(['page'=>$page,'pagesize'=>$pagesize]);
return $s->GetInfoList(['cname'=>$cname,'status'=>$status,'departmentid'=>$departmentid,'page'=>$page,'pagesize'=>$pagesize]);
}
public function Save(){
$userInfo =request('userInfo');
@ -36,6 +39,17 @@ class UserController extends Controller
}
}
//重置密码
public function resetPwd(Request $request)
{
$group = $request->get('role');//中间件产生的参数
$password =request('password');
$userid=request('userid');
if(!isset($password)) return \Yz::echoError1('请输入密码');
if(!isset($userid)) return \Yz::echoError1('用户id不能为空');
$service= new UserService();
return $service->resetPwd($group,$password,$userid);
}
//修改自身信息
public function ChangInfo(Request $request){

@ -3,6 +3,7 @@
namespace App\Http\Controllers\API\Admin\YeWu;
use App\Http\Controllers\Controller;
use App\Services\Admin\YeWu\PlanListService;
use DateTime;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@ -29,6 +30,35 @@ class PlanListController extends Controller
}
$start_date = new DateTime($dateRange[0]);
$end_date = new DateTime($dateRange[1]);
//查询是否有重复插入
$checkList = DB::table('s_source_roster_detail')
->where('department_id', $department_id)
->whereIn('roster_id', $planModelIds)
->where('date', '>=', $start_date->format('Y-m-d'))
->where('date', '<=', $end_date->format('Y-m-d'))
->where('is_del', 0)
->get();
$msg='</br>当前选中的';
$msglist='';
$msgIds='';
if (count($checkList) > 0) {
foreach ($models as $model ){
foreach ($checkList as $item) {
$msglist.=$item->date.' ';
$msgIds.=$item->id.' ';
}
if($item->roster_id==$model->id){
$msg.=" ".$model->weekname.$model->begin_time.'-'.$model->end_time." ";
}
}
return \Yz::Return(false,'已有重复的计划明细,禁止创建!'.$msg.'已存在相同记录,</br>存在于:</br>'.$msglist.'</br>对应记录Id为'.$msgIds.'</br>请先删除后再操作', $checkList);
}
// 循环日期并判断星期
$current_date = clone $start_date;
DB::beginTransaction();
@ -79,6 +109,9 @@ class PlanListController extends Controller
'adduser' => $userid,
'is_del' => 0,
];
$plan_id = DB::table('s_source_roster_detail')->insertGetId($data);
// 插入数量表
$model_count_info = DB::table('s_source_roster_count')->where(['roster_id' => $model->id])->get();
@ -92,7 +125,7 @@ class PlanListController extends Controller
]);
if (!$i_c) {
DB::rollBack();
return \Yz::echoError1('保存失败');
return \Yz::echoError1('创建失败');
}
}
} else {
@ -106,7 +139,7 @@ class PlanListController extends Controller
$current_date->modify('+1 day');
}
DB::commit();
return \Yz::Return(true, '保存成功', []);
return \Yz::Return(true, '创建成功', []);
}
}
@ -259,55 +292,14 @@ class PlanListController extends Controller
//获取可用的计划,用于计划占用
public function GetEnablePlan()
{
date_default_timezone_set('PRC');
$regnum = request('regnum');
$entrustid = request('entrustid');
$episodeid = request('episodeid');
$appointment_type = request('appointment_type'); //预约类型
$appointment_date = request('date'); //预约日期
$info = DB::table('s_list')->where(['reg_num' => $regnum, 'entrust_id' => $entrustid, 'episodeid' => $episodeid])->first();
if (!$info) return \Yz::echoError1('没有找到对应医嘱信息');
$itemInfo = DB::table('s_check_item')->where(['item_name' => $info->entrust, 'status' => 1, "is_del" => 0])->get();
if (count($itemInfo) == 0) return \Yz::echoError1('没有找到可用的检查项目信息');
$itemInfo = $itemInfo[0];
$qudaos = explode(',', $itemInfo->reservation_method);
if (!in_array($appointment_type, $qudaos)) return \Yz::echoError1('此检查项目不支持在当前渠道预约');
$entrust_time = $info->entrust_date . ' ' . $info->entrust_time; //医嘱时间
$date = new DateTime($entrust_time);
$date->modify("+" . $itemInfo->check_begin_time . " minutes");
$enableCheckTime = $date;//到此时间后可进行预约
$current_time = new DateTime();
if ($current_time < $enableCheckTime) return \Yz::echoError1("请于" . $enableCheckTime->format("Y-m-d H:i:s") . "后进行预约");
//获取检查项目绑定的服务组(设备),判断状态正常的
$devices = DB::table('s_check_item_device')
->leftJoin("s_devices", "s_check_item_device.device_id", "=", "s_devices.id")
->where(['s_check_item_device.item_id' => $itemInfo->id])
->where(['s_devices.status' => 1, 'is_del' => 0])->pluck('s_devices.id')->toArray();
//获取主表检查项目绑定的科室id
$department_id = DB::table('s_department')->where(['department_number' => $info->RISRAcceptDeptCode])->first();
if (!$department_id) return \Yz::echoError1('获取医嘱检查项目科室信息失败');
//获取对应日期的计划明细
$plan = DB::table('s_source_roster_detail as a')
->select('a.*', 'b.department_resources_name', 'c.roster_detail_id', 'c.count', 'c.used_count')
->leftJoin('s_department_resources as b', 'a.resources_id', '=', 'b.id')
->leftJoin('s_source_roster_detail_count as c', 'a.id', '=', 'c.roster_detail_id')
->where(['a.department_id' => $department_id->id, 'a.date' => $appointment_date, 'a.status' => 1, 'a.is_del' => 0, 'b.is_del' => 0, 'c.appointment_type_id' => $appointment_type])->get();
$plan_enable = [];
foreach ($plan as $key => $value) {
if (array_intersect($devices, array_map('intval', explode(',', $value->device_id)))) {
$plan_enable[] = $value;
}
}
return \Yz::Return(true, '查询完成', ['today_date' => date("Y-m-d"), 'appointment_date' => $appointment_date, 'weekname' => Tools::GetWeekName($appointment_date), 'mainInfo' => $info, 'plan_list' => $plan_enable]);
$service = new PlanListService();
return $service->GetEnablePlan($regnum,$entrustid,$episodeid,$appointment_type,$appointment_date);
}
//开始预约占用名额
@ -321,153 +313,70 @@ class PlanListController extends Controller
$do_type = request('dotype');//操作类型,1预约2改约
if (!isset($do_type)) return \Yz::echoError1('参数:操作类型 不能为空');
$mainInfo = DB::table('s_list')->where(['id' => $mainlistid])->first();
if (!$mainInfo) return \Yz::echoError1('医嘱不存在');
//判断状态
if ($do_type == 1 && $mainInfo->list_status <> 0) return \Yz::echoError1('该信息状态不允许预约,当前状态:' . $mainInfo->list_status);
if ($do_type == 2 && $mainInfo->list_status <> 1) return \Yz::echoError1('该信息状态不允许改约操作,当前状态:' . $mainInfo->list_status);
$planInfo = DB::table('s_source_roster_detail')->where(['id' => $planid, 'status' => 1, 'is_del' => 0])->first();
if (!$planInfo) return \Yz::echoError1('当前时段不可用');
if ($nowdatetime > $planInfo->date . ' ' . $planInfo->end_reservation_time) return \Yz::echoError1('已经超过预约截止时间');
$planCount = DB::table('s_source_roster_detail_count')->where(['roster_detail_id' => $planid,
'appointment_type_id' => $appointment_type])->first();
if ($planCount->count <= $planCount->used_count) return \Yz::echoError1('当前预约时间已无名额');
//判断互斥暂时根据reg_num判断身份
//查询想要预约的项目 其自身code
$item=DB::table('s_check_item')->where(['item_name'=>$mainInfo->entrust,'status'=>1,'is_del'=>0])->first();
if(!$item) return \Yz::echoError1('此检查项目不可用');
//查询当前检查项目是否存在互斥
$cha_hc=DB::table('s_huchi')->where('is_del',0)
->where(function ($q) use($item) {
$q->where(['code1'=>$item->item_code])->orWhere('code2',$item->item_code);
})->get();
if(count($cha_hc)>0){
//查询用户预约中的医嘱
$status_1=DB::table('s_list')
->select('s_check_item.item_code','s_list.entrust','s_list.reservation_date','s_list.reservation_time')
->leftJoin('s_check_item','s_list.entrust','=','s_check_item.item_name')
->where(['s_list.reg_num'=>$mainInfo->reg_num,'s_list.list_status'=>1,'s_list.is_del'=>0,'s_list.is_nullify'=>0])->get();
if(count($status_1)>0){
foreach ($status_1 as $key=>$value){
foreach ($cha_hc as $k=>$v){
if($v->code1==$value->item_code or $v->code2==$value->item_code){
if($v->time==0){
//如果是永久互斥,直接拒绝
return \Yz::Return(false, '当前预约项目与'.$value->entrust.'互斥,暂不可预约', ['name'=>$value->entrust]);
}
if($v->time>0){
//如果设置互斥时间,则判断预约时间是否超过 正在预约的最后时间段+互斥时间
$period=DB::table('s_period')->where(['id'=>$value->reservation_time])->first();
$endTime=$period->period_end_time;
$periodEndDateTime=$value->reservation_date.' '.$endTime;
$date = new DateTime($periodEndDateTime);
// 添加互斥时间/小时
$date->add(new \DateInterval('PT'.$v->time.'H')); // PTXH 表示X小时的时间间隔
$HuChi_EndDateTime = $date->format('Y-m-d H:i:s');//已经预约的项目结束互斥时间
$YuYueDateTime=substr($planInfo->date,0,10) .' '.$planInfo->begin_time;
if($HuChi_EndDateTime>$YuYueDateTime){
return \Yz::Return(false, '当前预约项目与'.$value->entrust.'互斥,暂不可预约,请预约'.$HuChi_EndDateTime.'后的日期', ['name'=>$value->entrust]);
}
}
}
}
}
}
}
DB::beginTransaction();
try {
//更新计划明细表使用数量
$u = DB::table('s_source_roster_detail_count')->where(['id' => $planCount->id])->where('count', '>', 'used_count')->increment('used_count');
if ($u) {
$cha = DB::table('s_source_roster_detail_count')->where(['id' => $planCount->id])->first();
if ($cha->count >= $cha->used_count) {
//更新主表信息
$u_mainList = DB::table('s_list')->where(['id' => $mainlistid])->update([
'list_status' => 1,
'reservation_date' => $planInfo->date,
'reservation_time' => $planInfo->period_id,
'reservation_sources' => $planInfo->resources_id,
'services_group' => $planInfo->device_id,
'roster_id' => $planInfo->id,
'xuhao' => 0,
'appointment_type_id' => $appointment_type,
]);
if ($do_type == 2) {
//如果是改约,则恢复原来的数量
$u_old = DB::table('s_source_roster_detail_count')->where(['roster_detail_id' => $mainInfo->roster_id, 'appointment_type_id' => $mainInfo->appointment_type_id])->decrement('used_count');
}
if ($u_mainList) {
DB::commit();
return \Yz::Return(true, '预约成功', []);
} else {
DB::rollBack();
return \Yz::echoError1('预约失败');
}
} else {
DB::rollBack();
return \Yz::echoError1('当前预约时间已无名额');
}
} else {
return \Yz::echoError1('操作失败');
}
} catch (\Exception $e) {
DB::rollBack();
return \Yz::echoError1('预约异常');
}
$service = new PlanListService();
return $service->YuYue($planid,$appointment_type,$mainlistid,$do_type);
}
public function CancelYuYue(Request $request)
{
date_default_timezone_set('PRC');
$nowdatetime = date("Y-m-d H:i:s");
// date_default_timezone_set('PRC');
// $nowdatetime = date("Y-m-d H:i:s");
$MainListId = request('MainListId');
$reg_num = request('reg_num');
$password = request('password');
$userid = $request->get('userid');//中间件产生的参数
$query = DB::table('users')->where(['id' => $userid])->get();
if(password_verify($password,$query[0]->pwd)) {
$mainInfo = DB::table('s_list')->where(['id' => $MainListId])->first();
if (!$mainInfo) return \Yz::echoError1('医嘱不存在');
//判断状态
if ($mainInfo->list_status <> 1) return \Yz::echoError1('该记录无法取消,当前状态:' . $mainInfo->list_status);
DB::beginTransaction();
try {
$u_mainList = DB::table('s_list')->where(['id' => $MainListId])->update([
'list_status' => 0,
'reservation_date' => null,
'reservation_time' => null,
'reservation_sources' =>null,
'services_group' => null,
'roster_id' => null,
'xuhao' => null,
'appointment_type_id' => null,
'canel_time'=>$nowdatetime,
]);
$u_count = DB::table('s_source_roster_detail_count')->where(['roster_detail_id' => $mainInfo->roster_id, 'appointment_type_id' => $mainInfo->appointment_type_id])->decrement('used_count');
if($u_mainList && $u_count){
DB::commit();
return \Yz::Return(true, '取消成功', []);
}else{
DB::rollBack();
return \Yz::echoError1('取消失败');
}
} catch (\Exception $e) {
DB::rollBack();
return \Yz::echoError1('取消异常');
}
$service = new PlanListService();
return $service->CancelYuYue($MainListId,$reg_num);
// $mainInfo = DB::table('s_list')->where(['id' => $MainListId])->first();
// if (!$mainInfo) return \Yz::echoError1('医嘱不存在');
// //判断状态
// if ($mainInfo->list_status <> 1) return \Yz::echoError1('该记录无法取消,当前状态:' . $mainInfo->list_status);
// DB::beginTransaction();
// try {
// $u_mainList = DB::table('s_list')->where(['id' => $MainListId])->update([
// 'list_status' => 0,
// 'reservation_date' => null,
// 'reservation_time' => null,
// 'reservation_sources' =>null,
// 'services_group' => null,
// 'roster_id' => null,
// 'xuhao' => null,
// 'appointment_type_id' => null,
// 'canel_time'=>$nowdatetime,
// ]);
// $u_count = DB::table('s_source_roster_detail_count')->where(['roster_detail_id' => $mainInfo->roster_id, 'appointment_type_id' => $mainInfo->appointment_type_id])->decrement('used_count');
// if($u_mainList && $u_count){
// DB::commit();
// return \Yz::Return(true, '取消成功', []);
// }else{
// DB::rollBack();
// return \Yz::echoError1('取消失败');
// }
// } catch (\Exception $e) {
// DB::rollBack();
// return \Yz::echoError1('取消异常');
// }
}else{
return \Yz::echoError1('密码不正确');
}
}
//查询已预约明细
public function GetUsedList()
{
$planid = request('planid');
$qudaoid= request('qudaoid');
$list=DB::table('s_list')
->leftJoin('s_department_resources','s_list.reservation_sources','=','s_department_resources.id')
->select('s_list.*','s_department_resources.department_resources_name')
->where(['s_list.roster_id'=>$planid,'s_list.appointment_type_id'=>$qudaoid,'s_list.is_del'=>0,'s_list.is_nullify'=>0])->whereIn('s_list.list_status',[1,2,3])->get();
return \Yz::Return(true,'查询完成',$list);
}
}

@ -18,7 +18,7 @@ class PlanModelController extends Controller
$department_id = 0;
$list = DB::table('s_source_roster')
->leftJoin('s_department_resources', 's_source_roster.resources_id', '=', 's_department_resources.id')
// ->leftJoin('s_devices', 's_source_roster.device_id', '=', 's_devices.id')
// ->leftJoin('s_devices', 's_source_roster.device_id', '=', 's_devices.id')
->leftJoin('s_period', 's_source_roster.period_id', '=', 's_period.id')
->select('s_source_roster.*', 's_department_resources.department_resources_name', 's_period.period_name')
->where(['s_source_roster.is_del' => 0]);
@ -33,14 +33,14 @@ class PlanModelController extends Controller
$list = $list->where(['s_source_roster.department_id' => $department_id]);
}
if (!empty($searchInfo['resources_id'])) {
$list = $list->where('s_source_roster.resources_id', $searchInfo['resources_id'] );
$list = $list->where('s_source_roster.resources_id', $searchInfo['resources_id']);
}
if (!empty($searchInfo['device_id'])) {
//$list = $list->where('s_source_roster.device_id', 'like','%,'.$searchInfo['device_id'].',%' );
$list = $list->whereRaw("FIND_IN_SET({$searchInfo['device_id']}, s_source_roster.device_id)");
}
if (!empty($searchInfo['xingqi'])) {
$list = $list->where('s_source_roster.weekname', $searchInfo['xingqi'] );
$list = $list->where('s_source_roster.weekname', $searchInfo['xingqi']);
}
if (isset($searchInfo['status'])) {
@ -49,7 +49,7 @@ class PlanModelController extends Controller
$count = $list;
$count = $count->count();
$list = $list->orderBy('id','desc')->limit($pageSize)->skip(($page - 1) * $pageSize) // 跳过前9999条记录
$list = $list->orderBy('id', 'desc')->limit($pageSize)->skip(($page - 1) * $pageSize) // 跳过前9999条记录
->take($pageSize)->get();
$ids = [];
foreach ($list as $key => $value) {
@ -90,7 +90,7 @@ class PlanModelController extends Controller
{
$userid = $request->get('userid');//中间件产生的参数
$bitian = array('xingqi', 'max_total', 'qudao_total', 'period_id', 'begin_time', 'end_time', 'end_reservation_time', 'resources_id', 'devices', 'patientType');
$bitian_zh = array('星期', '当日总量', '渠道数量', '时间段', '开始时间', '结束时间', '停止预约时间', '资源', '设备', '患者类型');
$bitian_zh = array('星期', '当日总量', '渠道数量', '时间段', '开始时间', '结束时间', '停止预约时间', '资源', '设备', '患者类型');
$planInfo = request('planInfo');
foreach ($bitian as $key => $field) { //必填项不能为空
if (array_key_exists($field, $planInfo) && $planInfo[$field] !== '' && $planInfo[$field] !== null && $planInfo[$field] !== [] && $planInfo[$field] !== 0) {
@ -104,13 +104,13 @@ class PlanModelController extends Controller
DB::beginTransaction();
foreach ($planInfo['xingqi'] as $key => $value) {
$data=[
$data = [
'department_id' => $department_id,
'weekname' => $value,
'resources_id' => $planInfo['resources_id'],
'device_id' => isset($planInfo['devices'])?implode(',', $planInfo['devices']):'',
'device_id' => isset($planInfo['devices']) ? implode(',', $planInfo['devices']) : '',
'period_id' => $planInfo['period_id'], //时间段id
'patient_type' =>isset($planInfo['patientType'])?implode(',', $planInfo['patientType']):'',//病人类型
'patient_type' => isset($planInfo['patientType']) ? implode(',', $planInfo['patientType']) : '',//病人类型
'begin_time' => $planInfo['begin_time'],
'end_time' => $planInfo['end_time'],
'end_reservation_time' => $planInfo['end_reservation_time'],
@ -118,22 +118,49 @@ class PlanModelController extends Controller
'status' => $planInfo['status'],
'adduser' => $userid,
];
if($planInfo['id']==0){//新增
//判断记录是否存在
$is_ex=DB::table('s_source_roster')->where([
'department_id' => $department_id,
'weekname' => $value,
'resources_id' => $planInfo['resources_id'],
'period_id' => $planInfo['period_id'], //时间段id
])->get();
if(count($is_ex)>0){
if($planInfo['end_reservation_time']>$planInfo['end_time']) return \Yz::echoError1('截止时间不能超过结束时间');
//判断记录是否存在
$is_ex = DB::table('s_source_roster')->where([
'department_id' => $department_id,
'weekname' => $value,
'resources_id' => $planInfo['resources_id'],
// 'period_id' => $planInfo['period_id'], //时间段id
'is_del' => 0,
]);
if ($planInfo['id'] > 0) {
$is_ex = $is_ex->where('id', '<>', $planInfo['id']);
}
$start = $planInfo['begin_time'];
$end = $planInfo['end_time'];
$is_ex = $is_ex->where(function ($query) use ($start, $end) {
// 情况1开始时间在查询区间内
$query->whereBetween('begin_time', [$start, $end])
->orWhereBetween('end_time', [$start, $end]);
// 情况2查询区间的开始时间在数据库记录的开始和结束时间之间
// 注意:对于时间类型的比较,直接使用字符串比较可能不够精确,特别是跨天情况,以下逻辑需根据实际情况调整
$query->orWhere(function ($query) use ($start, $end) {
$query->where('begin_time', '<=', $start)
->where('end_time', '>=', $end);
});
})->get();
// dd($is_ex);
//遍历判断设备是否有重叠,有则返回错误
foreach ($is_ex as $k => $v) {
$db_device_ids = explode(',', $v->device_id);
$overlap = array_intersect($planInfo['devices'], $db_device_ids);
if (count($overlap) > 0) {
DB::rollBack();
return \Yz::echoError1($value.'已存在相同记录,id为:'.$is_ex[0]->id);
return \Yz::echoError1($value . '时段服务组关联重复,计划id为:' . $v->id);
}
$roster_id=DB::table('s_source_roster')->insertGetId($data);
}
if ($planInfo['id'] == 0) {//新增
$roster_id = DB::table('s_source_roster')->insertGetId($data);
if ($roster_id) {
foreach ($planInfo['qudao_total'] as $k => $v) {
$i_c=DB::table('s_source_roster_count')->insert([
$i_c = DB::table('s_source_roster_count')->insert([
'roster_id' => $roster_id,
'appointment_type_id' => $v['id'],
'max_total' => $planInfo['max_total'],
@ -148,19 +175,20 @@ class PlanModelController extends Controller
DB::rollBack();
return \Yz::echoError1('保存失败');
}
}else{//修改
$data['id']=$planInfo['id'];
} else {//修改
$data['id'] = $planInfo['id'];
$i=DB::table('s_source_roster')->where(['id'=>$planInfo['id'],'is_del'=>0])->update($data);
$i = DB::table('s_source_roster')->where(['id' => $planInfo['id'], 'is_del' => 0])->update($data);
foreach ($planInfo['qudao_total'] as $k => $v) {
$i_c=DB::table('s_source_roster_count')->where(['roster_id'=>$planInfo['id'],'appointment_type_id'=>$v['appointment_type_id']])->update([
'max_total' => $planInfo['max_total'],
'count' => $v['count'],
]);
foreach ($planInfo['qudao_total'] as $k => $v) {
$i_c = DB::table('s_source_roster_count')->where(['roster_id' => $planInfo['id'], 'appointment_type_id' => $v['appointment_type_id']])->update([
'max_total' => $planInfo['max_total'],
'count' => $v['count'],
]);
}
if ($i or $i_c) { } else {
}
if ($i or $i_c) {
} else {
DB::rollBack();
return \Yz::echoError1('保存失败');
}
@ -170,19 +198,20 @@ class PlanModelController extends Controller
DB::commit();
return \Yz::Return(true, '保存成功', []);
}
//获取模板信息详情
public function GetDetailInfo()
{
$id = request('id');
$info = DB::table('s_source_roster')->where(['id' => $id])->first();
if (!!$info) {
$info->devices =array_map('intval',explode(',', $info->device_id)) ;
$info->devices = array_map('intval', explode(',', $info->device_id));
$info->patientType = explode(',', $info->patient_type);
$info->qudao_total = DB::table('s_source_roster_count')
->select('s_source_roster_count.*', 's_appointment_type.name')
->leftJoin('s_appointment_type', 's_source_roster_count.appointment_type_id', '=', 's_appointment_type.id')
->where(['roster_id' => $id])->get();
$ratio= DB::table('s_appointment_type_ratio')
$ratio = DB::table('s_appointment_type_ratio')
->where(['department_id' => $info->department_id])->get();
foreach ($info->qudao_total as $key => $value) {
foreach ($ratio as $k => $v) {
@ -192,11 +221,12 @@ class PlanModelController extends Controller
}
}
return \Yz::Return(true, '操作成功', $info);
}else{
} else {
return \Yz::echoError1('数据不存在');
}
}
//获取自己的预约类型比例
public function GetAppointmentRatio(Request $request)
{
@ -219,6 +249,7 @@ class PlanModelController extends Controller
return \Yz::Return(true, '操作成功', $appointment_type);
}
}
//保存预约类型比例
public function SaveAppointmentRatio(Request $request)
{
@ -231,15 +262,15 @@ class PlanModelController extends Controller
DB::table('s_appointment_type_ratio')->where(['department_id' => $department_id])->delete();
foreach ($ratioInfo as $key => $value) {
$u=DB::table('s_appointment_type_ratio')->insert([
$u = DB::table('s_appointment_type_ratio')->insert([
'department_id' => $department_id,
'appointment_type_id' => $value['id'],
'ratio' => $value['ratio'],
]);
}
if($u){
if ($u) {
return \Yz::Return(true, '操作成功', []);
}else{
} else {
return \Yz::echoError1('保存失败,无数据更新');
}
@ -255,13 +286,13 @@ class PlanModelController extends Controller
if (!!$userInfo) {
$appointment_type = DB::table('s_appointment_type')->where(['status' => 1, 'is_del' => 0])->get();
$department_id = $userInfo->department_id;
$d= DB::table('s_source_roster')
->where(['department_id' => $department_id])->whereIn('id',$ids)->update([
'is_del'=>1,
$d = DB::table('s_source_roster')
->where(['department_id' => $department_id])->whereIn('id', $ids)->update([
'is_del' => 1,
]);
if($d){
if ($d) {
return \Yz::Return(true, '操作成功', []);
}else{
} else {
return \Yz::echoError1('操作失败');
}

@ -18,7 +18,7 @@ class TimePeriodController extends Controller
if(isset($PeriodInfo['department_name'])){
unset($PeriodInfo['department_name']);
}
if($PeriodInfo['period_deadline']>=$PeriodInfo['period_end_time']) return \Yz::echoError1('截止时间不能超过结束时间');
if($PeriodInfo['period_deadline']>$PeriodInfo['period_end_time']) return \Yz::echoError1('截止时间不能超过结束时间');
if($PeriodInfo['id']==0){
$userid = $request->get('userid');//中间件产生的参数
$userInfo = DB::table('users')->where(['id'=>$userid])->get();

@ -45,7 +45,11 @@ class WorkMainController extends Controller
->where(['RISRAcceptDeptCode'=>$department->department_number]);
if ($searchInfo['dateRange']!=null and count($searchInfo['dateRange']) == 2) {
$list = $list->whereBetween('s_list.entrust_date', $searchInfo['dateRange']);
$list = $list->where(function ($q) use($searchInfo) {
$q->whereBetween('s_list.entrust_date', $searchInfo['dateRange'])
->orWhereBetween('s_list.reservation_date', $searchInfo['dateRange']);
});
}
if (isset($searchInfo['list_status'])) {
$list = $list->where('s_list.list_status', $searchInfo['list_status']);
@ -53,6 +57,12 @@ class WorkMainController extends Controller
if (isset($searchInfo['patient_type'])) {
$list = $list->where('s_list.patient_type', $searchInfo['patient_type']);
}
if (!empty($searchInfo['resources'])) {
$list = $list->whereIn('s_list.reservation_sources', $searchInfo['resources']);
}
if (isset($searchInfo['services_group'])) {
$list = $list->whereRaw("FIND_IN_SET({$searchInfo['services_group']}, s_list.services_group)");
}
if (isset($searchInfo['reg_num'])) {
$list = $list->where('s_list.reg_num', $searchInfo['reg_num']);
}
@ -80,7 +90,13 @@ class WorkMainController extends Controller
return \Yz::Return(true,'查询完成',['list'=>$list,'count'=>$count]);
}
//计算年龄
//获取医嘱变更日志
public function GetLoglist()
{
$id = request('id');
$List=DB::table('s_list_log')->where(['list_id'=>$id])->get();
return \Yz::Return(true,'查询完成',$List);
}
}

@ -0,0 +1,42 @@
<?php
namespace App\Http\Controllers\API\H5;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class EntrustController extends Controller
{
public function GetList(Request $request)
{
$searchInfo = request('searchInfo');
$userid = $request->get('userid');//中间件产生的参数
$list=DB::table('s_list')
->leftJoin('s_period','s_list.reservation_time','=','s_period.id')
->leftJoin('s_department_resources','s_list.reservation_sources','=','s_department_resources.id')
->select('s_list.*','s_period.period_begin_time','s_period.period_end_time','s_department_resources.department_resources_name')
->where(['s_list.is_del'=>0,'s_list.is_nullify'=>0])
->where('s_list.reg_num', $userid);
if ($searchInfo['dateRange']!=null and count($searchInfo['dateRange']) == 2) {
$list = $list->whereBetween('s_list.entrust_date', $searchInfo['dateRange']);
}
$count = $list;
$count = $count->count();
$list=$list->orderBy('id', 'desc')->get();
return \Yz::Return(true,'查询完成',['list'=>$list,'count'=>$count]);
}
}

@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\API\H5;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use JWT;
class LoginController extends Controller
{
public function Login()
{
$jwt= new JWT();
$accessTimeout = $jwt -> GetGetSecretTimeOut();
$refreshTimeout = $jwt -> GetRefreshTokenTimeOut();
$access_token = $jwt->BuildJWT('yz','access','0001289649',666,$accessTimeout);
$refresh_token = $jwt->BuildJWT('yz','refresh',9999,'',$refreshTimeout);
$result['token']=$access_token;
$result['refresh_token']=$refresh_token;
return \Yz::Return(true,'登陆成功',$result);
}
}

@ -0,0 +1,46 @@
<?php
namespace App\Http\Controllers\API\H5;
use App\Http\Controllers\Controller;
use App\Services\Admin\YeWu\PlanListService;
use Illuminate\Http\Request;
class PlanController extends Controller
{
public function GetEnablePlan(Request $request)
{
$regnum = request('regnum');
$entrustid = request('entrustid');
$episodeid = request('episodeid');
$appointment_type = request('appointment_type'); //预约类型
$appointment_date = request('date'); //预约日期
$userid = $request->get('userid');//中间件产生的参数
$service = new PlanListService();
return $service->GetEnablePlan($userid,$entrustid,$episodeid,$appointment_type,$appointment_date);
}
public function H5_YuYue()
{
$p=[
'planid'=>request('planid'),
'appointment_type'=>request('appointment_type'),//渠道id
'mainlistid'=>request('mainlistid'),
'do_type'=>request('do_type'),//操作类型,1预约2改约
];
foreach ($p as $key=>$value){
if(!isset($value)){
return \Yz::echoError1('参数:'.$key.' 不能为空');
}
}
$service = new PlanListService();
return $service->YuYue($p['planid'],$p['appointment_type'],$p['mainlistid'],$p['do_type']);
}
public function H5_CancelYuYue(Request $request)
{
$userid = $request->get('userid');//中间件产生的参数
$MainListId = request('MainListId');
$service = new PlanListService();
return $service->CancelYuYue($MainListId,$userid);
}
}

@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class ToolsController extends Controller
{
//获取当前服务器时间
public function GetServiceDateTime()
{
date_default_timezone_set('PRC');
$d=date("Y-m-d H:i:s");
//$d=('2022-12-31 12:12:12');
return \Yz::Return(true,'获取成功',['datetime'=>$d]);
}
}

@ -27,6 +27,7 @@ class Log
// 在关联数组中添加 code 字段
// $data['code'] = 200;
$data['code'] = $response->getStatusCode();
$modifiedContent = json_encode($data); // 编码修改后的关联数组为 JSON 字符串
$response->setContent($modifiedContent);
if(env('REQUEST_LOG') and $response->getStatusCode()==200){ //如果返回状态为200进行log

@ -6,10 +6,25 @@ use App\Services\Login\LoginService;
class UserService
{
public function GetInfoList($arr){
$q=DB::select("select a.id, a.cn_name as cname,a.username as uname,a.status,a.created_at,b.group_name from users as a left join `group` as b on a.`group` =b.id where a.status in(0,1) limit ?,?",[($arr['page']-1)*$arr['pagesize'],$arr['pagesize']]);
$count=DB::select("select count(1) as c from users as a left join `group` as b on a.`group` =b.id where a.status in(0,1)");
$result['list']=$q;
$result['count']=$count[0]->c;
$list=DB::table('users as a')
->select( 'a.id', 'a.cn_name as cname','a.username as uname','a.status','a.created_at','b.group_name','c.department_name')
->leftJoin('group as b','a.group','=','b.id')
->leftJoin('s_department as c','a.department_id','=','c.id');
if(isset($arr['status'])){
$list=$list->where(['a.status'=>$arr['status']]);
}
if(isset($arr['cname'])){
$list=$list->where('a.cn_name', 'like', '%'.$arr['cname'].'%');
}
if(isset($arr['departmentid'])){
$list=$list->where('a.department_id', $arr['departmentid']);
}
$count=$list->count();
$list=$list
->skip(($arr['page']-1)*$arr['pagesize']) // 跳过前9999条记录
->take($arr['pagesize'])->get();
$result['list']=$list;
$result['count']=$count;
return $result;
}
public function Save($arr){
@ -93,6 +108,23 @@ class UserService
}
return $result;
}
//重置密码
public function resetPwd($group,$password,$userid)
{
$result=array();
// dd($group);
if($group==1){
$hash = password_hash($password, PASSWORD_DEFAULT);
$u=DB::table('users')->where(['id'=>$userid,'status'=>1])->update(['pwd'=>$hash]);
if($u){
return \Yz::return(true,'操作成功',[]);
}else{
return \Yz::echoError1('操作失败');
}
}else{
return \Yz::echoError1('权限不足');
}
}
//检查用户是否有某个目录的权限
//参数['userid'=>$userid,'group'=>$group,'url'=>$url]

@ -33,11 +33,26 @@ class CheckItemService
$where[]=['item_name','like','%'.$searchInfo['name'].'%'];
}
$count= $list->where($where)->count();
$list= $list ->leftJoin('s_appointment_type', 's_check_item.reservation_method', '=', 's_appointment_type.id')
$list= $list
->leftJoin('s_appointment_type', 's_check_item.reservation_method', '=', 's_appointment_type.id')
->select('s_check_item.*','s_appointment_type.name as reservation_method_name')
->where($where)->skip(($page-1)*$pageSize) // 跳过前9999条记录
->take($pageSize)->get();
//查询出所有的预约渠道
$qudaoList=DB::table('s_appointment_type')->get();
foreach ($list as $k=>$v){
$qudao_names=[];
$qudao_ids = explode(",", $v->reservation_method);
foreach ($qudaoList as $k1=>$v1){
foreach ($qudao_ids as $k2=>$v2){
if($v1->id==$v2){
$qudao_names[]=$v1->name;
}
}
}
$list[$k]->reservation_method= array_map('intval', $qudao_ids);
$list[$k]->reservation_method_name=$qudao_names;
$list[$k]->devicesInfo=DB::table('s_check_item_device')
->join('s_devices', 's_check_item_device.device_id', '=', 's_devices.id')
->select('s_devices.*')
@ -67,6 +82,7 @@ class CheckItemService
}
public function Save($Info){
if(!empty($Info['id'])){
$Info['reservation_method']=implode(',', $Info['reservation_method']);
$res=DB::table('s_check_item')->where('id',$Info['id'])->update($Info);
if($res){
return \Yz::Return(true, '修改成功');

@ -0,0 +1,257 @@
<?php
namespace App\Services\Admin\YeWu;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use DateTime;
use Tools;
class PlanListService
{
public function GetEnablePlan($regnum, $entrustid, $episodeid, $appointment_type, $appointment_date)
{
date_default_timezone_set('PRC');
// $regnum = request('regnum');
// $entrustid = request('entrustid');
// $episodeid = request('episodeid');
// $appointment_type = request('appointment_type'); //预约类型
// $appointment_date = request('date'); //预约日期
$info = DB::table('s_list')->where(['reg_num' => $regnum, 'entrust_id' => $entrustid, 'episodeid' => $episodeid])->first();
if (!$info) return \Yz::echoError1('没有找到对应医嘱信息');
$itemInfo = DB::table('s_check_item')->where(['item_name' => $info->entrust, 'status' => 1, "is_del" => 0])->get();
if (count($itemInfo) == 0) return \Yz::echoError1('没有找到可用的检查项目信息');
$itemInfo = $itemInfo[0];
$qudaos = explode(',', $itemInfo->reservation_method);
if (!in_array($appointment_type, $qudaos)) return \Yz::echoError1('此检查项目不支持在当前渠道预约');
$entrust_time = $info->entrust_date . ' ' . $info->entrust_time; //医嘱时间
$date = new DateTime($entrust_time);
$date->modify("+" . $itemInfo->check_begin_time . " minutes");
$enableCheckTime = $date;//到此时间后可进行预约
$current_time = new DateTime();
if ($current_time < $enableCheckTime) return \Yz::echoError1("请于" . $enableCheckTime->format("Y-m-d H:i:s") . "后进行预约");
//获取检查项目绑定的服务组(设备),判断状态正常的
$devices = DB::table('s_check_item_device')
->leftJoin("s_devices", "s_check_item_device.device_id", "=", "s_devices.id")
->where(['s_check_item_device.item_id' => $itemInfo->id])
->where(['s_devices.status' => 1, 'is_del' => 0])->pluck('s_devices.id')->toArray();
//获取主表检查项目绑定的科室id
$department_id = DB::table('s_department')->where(['department_number' => $info->RISRAcceptDeptCode])->first();
if (!$department_id) return \Yz::echoError1('获取医嘱检查项目科室信息失败');
//获取对应日期的计划明细
$plan = DB::table('s_source_roster_detail as a')
->select('a.*', 'b.department_resources_name', 'c.roster_detail_id', 'c.count', 'c.used_count')
->leftJoin('s_department_resources as b', 'a.resources_id', '=', 'b.id')
->leftJoin('s_source_roster_detail_count as c', 'a.id', '=', 'c.roster_detail_id')
->where(['a.department_id' => $department_id->id, 'a.date' => $appointment_date, 'a.status' => 1, 'a.is_del' => 0, 'b.is_del' => 0, 'c.appointment_type_id' => $appointment_type])->get();
$plan_enable = [];
foreach ($plan as $key => $value) {
if (array_intersect($devices, array_map('intval', explode(',', $value->device_id)))) {
$plan_enable[] = $value;
}
}
//匹配设备(服务组)
$devices = DB::table('s_devices')->get();
foreach ($plan_enable as $key => $value){
// dd($value);
$plan_enable[$key]->devices = [];
$array_device_id = explode(",", $value->device_id);
$names='';
foreach ($devices as $k => $v) {
if (in_array($v->id, $array_device_id)) {
$names=$names. $v->device_name.' ';
}
}
$plan_enable[$key]->devices =$names;
}
return \Yz::Return(true, '查询完成', ['today_date' => date("Y-m-d"), 'appointment_date' => $appointment_date, 'weekname' => Tools::GetWeekName($appointment_date), 'mainInfo' => $info, 'plan_list' => $plan_enable]);
}
//开始预约占用名额
public function YuYue($planid, $appointment_type, $mainlistid, $do_type)
{
date_default_timezone_set('PRC');
$nowdatetime = date("Y-m-d H:i:s");
// $planid = request('planid');
// $appointment_type = request('appointment_type');//渠道id
// $mainlistid = request('mainlistid');//主表id
// $do_type = request('dotype');//操作类型,1预约2改约
// if (!isset($do_type)) return \Yz::echoError1('参数:操作类型 不能为空');
$mainInfo = DB::table('s_list')->where(['id' => $mainlistid])->first();
if (!$mainInfo) return \Yz::echoError1('医嘱不存在');
//判断状态
if ($do_type == 1 && $mainInfo->list_status <> 0) return \Yz::echoError1('该信息状态不允许预约,当前状态:' . $mainInfo->list_status);
if ($do_type == 2 && $mainInfo->list_status <> 1) return \Yz::echoError1('该信息状态不允许改约操作,当前状态:' . $mainInfo->list_status);
$planInfo = DB::table('s_source_roster_detail')->where(['id' => $planid, 'status' => 1, 'is_del' => 0])->first();
if (!$planInfo) return \Yz::echoError1('当前时段不可用');
if ($nowdatetime > $planInfo->date . ' ' . $planInfo->end_reservation_time) return \Yz::echoError1('已经超过预约截止时间');
$planCount = DB::table('s_source_roster_detail_count')->where(['roster_detail_id' => $planid,
'appointment_type_id' => $appointment_type])->first();
if ($planCount->count <= $planCount->used_count) return \Yz::echoError1('当前预约时间已无名额');
//判断互斥暂时根据reg_num判断身份
//查询想要预约的项目 其自身code
$item = DB::table('s_check_item')->where(['item_name' => $mainInfo->entrust, 'status' => 1, 'is_del' => 0])->first();
if (!$item) return \Yz::echoError1('此检查项目不可用');
//查询当前检查项目是否存在互斥
$cha_hc = DB::table('s_huchi')->where('is_del', 0)
->where(function ($q) use ($item) {
$q->where(['code1' => $item->item_code])->orWhere('code2', $item->item_code);
})->get();
if (count($cha_hc) > 0) {
//查询用户预约中的医嘱
$status_1 = DB::table('s_list')
->select('s_check_item.item_code', 's_list.entrust', 's_list.reservation_date', 's_list.reservation_time')
->leftJoin('s_check_item', 's_list.entrust', '=', 's_check_item.item_name')
->where(['s_list.reg_num' => $mainInfo->reg_num, 's_list.list_status' => 1, 's_list.is_del' => 0, 's_list.is_nullify' => 0])->get();
if (count($status_1) > 0) {
foreach ($status_1 as $key => $value) {
foreach ($cha_hc as $k => $v) {
if ($v->code1 == $value->item_code or $v->code2 == $value->item_code) {
if ($v->time == 0) {
//如果是永久互斥,直接拒绝
return \Yz::Return(false, '当前预约项目与' . $value->entrust . '互斥,暂不可预约', ['name' => $value->entrust]);
}
if ($v->time > 0) {
//如果设置互斥时间,则判断预约时间是否超过 正在预约的最后时间段+互斥时间
$period = DB::table('s_period')->where(['id' => $value->reservation_time])->first();
$endTime = $period->period_end_time;
$periodEndDateTime = $value->reservation_date . ' ' . $endTime;
$date = new DateTime($periodEndDateTime);
// 添加互斥时间/小时
$date->add(new \DateInterval('PT' . $v->time . 'H')); // PTXH 表示X小时的时间间隔
$HuChi_EndDateTime = $date->format('Y-m-d H:i:s');//已经预约的项目结束互斥时间
$YuYueDateTime = substr($planInfo->date, 0, 10) . ' ' . $planInfo->begin_time;
if ($HuChi_EndDateTime > $YuYueDateTime) {
return \Yz::Return(false, '当前预约项目与' . $value->entrust . '互斥,暂不可预约,请预约' . $HuChi_EndDateTime . '后的日期', ['name' => $value->entrust]);
}
}
}
}
}
}
}
DB::beginTransaction();
try {
//更新计划明细表使用数量
$u = DB::table('s_source_roster_detail_count')->where(['id' => $planCount->id])->where('count', '>', 'used_count')->increment('used_count');
if ($u) {
$cha = DB::table('s_source_roster_detail_count')->where(['id' => $planCount->id])->first();
if ($cha->count >= $cha->used_count) {
//更新主表信息
$u_data=[
'list_status' => 1,
'reservation_date' => $planInfo->date,
'reservation_time' => $planInfo->period_id,
'reservation_sources' => $planInfo->resources_id,
'services_group' => $planInfo->device_id,
'roster_id' => $planInfo->id,
'department_id'=>$planInfo->department_id,
'xuhao' => 0,
'appointment_type_id' => $appointment_type,
];
$u_mainList = DB::table('s_list')->where(['id' => $mainlistid])->update($u_data);
$note="预约";
if ($do_type == 2) {
$note="改约";
//如果是改约,则恢复原来的数量
$u_old = DB::table('s_source_roster_detail_count')->where(['roster_detail_id' => $mainInfo->roster_id, 'appointment_type_id' => $mainInfo->appointment_type_id])->decrement('used_count');
}
$i_log=DB::table('s_list_log')->insert([
'list_id'=>$mainlistid,
'reg_num'=>$mainInfo->reg_num,
'old_status'=>$mainInfo->list_status,
'new_status'=>1,
'create_user'=>null,
'note'=>$note,
'data'=>json_encode($u_data)
]);
if ($u_mainList) {
DB::commit();
return \Yz::Return(true, '预约成功', []);
} else {
DB::rollBack();
return \Yz::echoError1('预约失败');
}
} else {
DB::rollBack();
return \Yz::echoError1('当前预约时间已无名额');
}
} else {
return \Yz::echoError1('操作失败');
}
} catch (\Exception $e) {
DB::rollBack();
return \Yz::echoError1('预约异常');
}
}
public function CancelYuYue($MainListId, $reg_num)
{
date_default_timezone_set('PRC');
$nowdatetime = date("Y-m-d H:i:s");
$mainInfo = DB::table('s_list')->where(['id' => $MainListId,'reg_num'=>$reg_num])->first();
if (!$mainInfo) return \Yz::echoError1('医嘱不存在');
//判断状态
if ($mainInfo->list_status <> 1) return \Yz::echoError1('该记录无法取消,当前状态:' . $mainInfo->list_status);
DB::beginTransaction();
try {
$u_data=[
'list_status' => 0,
'reservation_date' => null,
'reservation_time' => null,
'reservation_sources' => null,
'services_group' => null,
'roster_id' => null,
'xuhao' => null,
'department_id'=>null,
'appointment_type_id' => null,
'canel_time' => $nowdatetime,
];
$u_mainList = DB::table('s_list')->where(['id' => $MainListId])->update($u_data);
$i_log=DB::table('s_list_log')->insert([
'list_id'=>$mainInfo->id,
'reg_num'=>$mainInfo->reg_num,
'old_status'=>$mainInfo->list_status,
'new_status'=>0,
'create_user'=>null,
'note'=>'取消预约',
'data'=>json_encode($u_data)
]);
$u_count = DB::table('s_source_roster_detail_count')->where(['roster_detail_id' => $mainInfo->roster_id, 'appointment_type_id' => $mainInfo->appointment_type_id])->decrement('used_count');
if ($u_mainList && $u_count) {
DB::commit();
return \Yz::Return(true, '取消成功', []);
} else {
DB::rollBack();
return \Yz::echoError1('取消失败');
}
} catch (\Exception $e) {
DB::rollBack();
return \Yz::echoError1('取消异常');
}
}
}

@ -122,7 +122,7 @@
regnum: getParameterByName('regnum'),
entrustid: getParameterByName('entrustid'),
episodeid: getParameterByName('episodeid'),
appointment_type: 1,
appointment_type: getParameterByName('appointment_type'),
date: date
}, function(data) {
$('#loadingModal').modal('hide');
@ -136,7 +136,7 @@
' <td>' + v.date + '</td>\n' +
' <td>' + v.weekname + '</td>\n' +
' <td>' + v.department_resources_name + '</td>\n' +
' <td>' + v.device_id + '</td>\n' +
' <td>' + v.devices + '</td>\n' +
' <td>' + v.begin_time + '-' + v.end_time + '</td>\n' +
' <td>' + v.used_count + '/' + v.count + '</td>\n' +
' </tr>')
@ -151,7 +151,7 @@
' <td>' + v.date + '</td>\n' +
' <td>' + v.weekname + '</td>\n' +
' <td>' + v.department_resources_name + '</td>\n' +
' <td>' + v.device_id + '</td>\n' +
' <td>' + v.devices + '</td>\n' +
' <td>' + v.begin_time + '-' + v.end_time + '</td>\n' +
' <td>' + v.used_count + '/' + v.count + '</td>\n' +
' </tr>')
@ -192,7 +192,7 @@
$.post(BaseUrl+'/api/admin/PlanYuYue', {
mainlistid:MainInfo.id,
planid: selectedId,
appointment_type: 1,
appointment_type:getParameterByName('appointment_type'),
dotype:getParameterByName('dotype'),//1预约2改约
}, function(data) {
@ -362,7 +362,7 @@
</div>
</div>
</div>
<div class="col-md-4" style="line-height: 36px" id="xingqi1">33333</div>
<div class="col-md-4" style="line-height: 36px" id="xingqi1"></div>
</div>
@ -403,7 +403,7 @@
</div>
</div>
</div>
<div class="col-md-4" style="line-height: 36px" id="xingqi2">33333</div>
<div class="col-md-4" style="line-height: 36px" id="xingqi2"></div>
</div>
<table id="table2">

@ -21,6 +21,8 @@ Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
Route::post('admin/login','App\Http\Controllers\API\Admin\LoginController@Login')->middleware('log'); //登录
Route::post('/tokenRefresh','App\Http\Controllers\API\TokenController@TokenRefresh')->middleware('log'); //刷新token
Route::post('/GetServiceDateTime','App\Http\Controllers\API\ToolsController@GetServiceDateTime')->middleware('log'); //获取当前服务器时间
Route::group(['middleware'=>['checktoken','log'],'prefix'=>'v1'],function () { //路由分组
Route::post('admin/getBaseMenuList','App\Http\Controllers\API\Admin\BaseInfoController@GetBaseMenuList'); //登录后获取admin后台用户对应菜单列表
@ -30,6 +32,7 @@ Route::group(['middleware'=>['checktoken','log'],'prefix'=>'v1'],function () {
Route::post('admin/AddMenu','App\Http\Controllers\API\Admin\MenuController@AddMenu'); //admin后台添加菜单
Route::post('admin/EditMenu','App\Http\Controllers\API\Admin\MenuController@EditMenu'); //admin后台修改菜单
Route::post('admin/getUserList','App\Http\Controllers\API\Admin\UserController@GetInfoList'); //admin后台获取用户列表
Route::post('admin/resetPwd','App\Http\Controllers\API\Admin\UserController@resetPwd'); //admin后台获重置用户密码
Route::post('admin/GetSystemUserDetail','App\Http\Controllers\API\Admin\UserController@GetDetail'); //admin后台获取用户详情
Route::post('admin/adminChangePwd','App\Http\Controllers\API\Admin\UserController@ChangePwd'); //admin后台修改密码
Route::post('admin/SaveSystemUserInfo','App\Http\Controllers\API\Admin\UserController@Save'); //admin后台保存用户信息
@ -81,9 +84,11 @@ Route::group(['middleware'=>['checktoken','log'],'prefix'=>'v1'],function () {
Route::post('admin/CreatePlanList','App\Http\Controllers\API\Admin\YeWu\PlanListController@Create');//生成计划明细
Route::post('admin/PlanListGetList','App\Http\Controllers\API\Admin\YeWu\PlanListController@GetList');//生成计划明细
Route::post('admin/PlanListGetDetail','App\Http\Controllers\API\Admin\YeWu\PlanListController@GetDetail');//计划详情
Route::post('admin/GetPlanUsedList','App\Http\Controllers\API\Admin\YeWu\PlanListController@GetUsedList');//计划占用详情列表
Route::post('admin/PlanDetailChangeInfo','App\Http\Controllers\API\Admin\YeWu\PlanListController@ChangeInfo');//修改计划详情信息
Route::post('admin/PlanListDel','App\Http\Controllers\API\Admin\YeWu\PlanListController@Del');//删除计划详情
Route::post('admin/GetMainList','App\Http\Controllers\API\Admin\YeWu\WorkMainController@GetList');//获取主表列表
Route::post('admin/GetLoglist','App\Http\Controllers\API\Admin\YeWu\WorkMainController@GetLoglist');//获取日志
Route::post('admin/CancelYuYue','App\Http\Controllers\API\Admin\YeWu\PlanListController@CancelYuYue');//取消预约
Route::post('admin/SetHuChi','App\Http\Controllers\API\Admin\YeWu\CheckItemController@SetHuChi');//设置互斥
Route::post('admin/DelHuChi','App\Http\Controllers\API\Admin\YeWu\CheckItemController@DelHuChi');//删除互斥
@ -95,8 +100,15 @@ Route::post('admin/getMainDetail','App\Http\Controllers\API\Admin\YeWu\WorkMainC
Route::post('admin/GetEnablePlan','App\Http\Controllers\API\Admin\YeWu\PlanListController@GetEnablePlan');//获取可用的计划,用于计划占用
Route::post('admin/PlanYuYue','App\Http\Controllers\API\Admin\YeWu\PlanListController@YuYue');//开始预约
//H5端接口
Route::post('H5/Login','App\Http\Controllers\API\H5\LoginController@Login');
Route::group(['middleware'=>['checktoken','log'],'prefix'=>'v1'],function () { //路由分组
Route::post('H5/EntrustGetList','App\Http\Controllers\API\H5\EntrustController@GetList');//获取个人医嘱列表
Route::post('H5/GetEnablePlan','App\Http\Controllers\API\H5\PlanController@GetEnablePlan');//获取可预约计划
Route::post('H5/H5_YuYue','App\Http\Controllers\API\H5\PlanController@H5_YuYue');//H5_预约
Route::post('H5/H5_CancelYuYue','App\Http\Controllers\API\H5\PlanController@H5_CancelYuYue');//H5_取消预约
});

@ -4,7 +4,7 @@
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>体检平台</title>
<title>医技预约</title>
</head>
<body>
<div id="app"></div>

@ -273,4 +273,22 @@ export const DelHuChi = (data = {}) => {
//获取互斥项
export const GetHuChiList = (data = {}) => {
return axios({ url: import.meta.env.VITE_APP_API + 'v1/admin/GetHuChiList', data: data })
}
//重置密码
export const resetPwd = (data = {}) => {
return axios({ url: import.meta.env.VITE_APP_API + 'v1/admin/resetPwd', data: data })
}
//获取当前服务器时间
export const GetServiceDateTime = (data = {}) => {
return axios({ url: import.meta.env.VITE_APP_API + 'GetServiceDateTime', data: data })
}
//获取计划占用列表
export const GetPlanUsedList = (data = {}) => {
return axios({ url: import.meta.env.VITE_APP_API + 'v1/admin/GetPlanUsedList', data: data })
}
//获取医嘱日志
export const GetLoglist = (data = {}) => {
return axios({ url: import.meta.env.VITE_APP_API + 'v1/admin/GetLoglist', data: data })
}

@ -3,7 +3,7 @@
<el-dialog v-model="dialogVisible" title="资源信息" width="30%" @close="close()">
<el-form :model="ResourcesInfo" label-width="100px" v-loading="loading" style="padding-right: 40px;">
<el-form-item label="所属科室:">
<el-select :filterable="true" clearable v-model="ResourcesInfo.department_id" placeholder="选择科室">
<el-select :filterable="true" clearable v-model="ResourcesInfo.department_id" placeholder="选择科室">
<el-option v-for="(item,index) in EnableDepartmentList" :key="index" :label="item.department_name" :value="item.id" />
</el-select>
</el-form-item>

@ -1,452 +1,513 @@
<template>
<div>
<div class="head">
<el-row>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.department_id" placeholder="选择科室"
style="margin-left: 8px;width: 150px;"
>
<el-option v-for="(item,index) in EnableDepartmentList" :key="index"
:label="item.department_name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.resources_id"
placeholder="选择资源"
style="margin-left: 8px;width: 150px;"
>
<el-option v-for="(item,index) in enableResourceList" :key="index"
:label="item.department_resources_name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.device_id"
placeholder="选择服务组"
style="margin-left: 8px;width: 150px;"
>
<el-option v-for="(item,index) in EnableDeviceList" :key="index"
:label="item.device_name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.xingqi"
placeholder="星期"
style="margin-left: 8px;width: 150px;"
>
<el-option v-for="(item,index) in xingqi" :key="index"
:label="item.label" :value="item.label" />
</el-select>
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.status"
placeholder="状态"
style="margin-left: 8px;width: 150px;"
>
<el-option label="正常" value="1" />
<el-option label="关闭" value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-date-picker style="margin-left: 8px; width: 300px"
v-model="searchInfo.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-button @click="GetList()" style="margin-left: 10px;">搜索</el-button>
<el-button type="danger" @click="Del()" style="margin-left: 10px;">删除</el-button>
</el-row>
</div>
<el-table :data="tableData" style="width: 100%;" row-key="id" v-loading="loading"
@selection-change="handleSelectionChange">
<el-table-column type="selection" />
<el-table-column prop="id" label="Id" />
<el-table-column prop="date" label="日期" >
<template #default="scope">
<span>{{ scope.row.date.substring(0, 10) }}</span>
</template>
</el-table-column>
<el-table-column prop="weekname" label="星期" />
<el-table-column prop="resources_id" label="" v-if="false" />
<el-table-column prop="department_resources_name" label="资源" />
<el-table-column prop="" label="服务组" show-overflow-tooltip >
<template #default="scope">
<div v-if="scope.row.devices.length>0">
<div v-for="(item,index) in scope.row.devices" :key="index"
:class="(item.status==1 && item.is_del==0) ? '':'hongzi'">{{ item.device_name }}
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="period_name" label="时段" />
<el-table-column prop="begin_time" label="开始时间" />
<el-table-column prop="end_time" label="结束时间" />
<el-table-column prop="end_reservation_time" label="截止时间" />
<el-table-column prop="" label="类型数量" show-overflow-tooltip width="250">
<template #default="scope">
<div v-if="scope.row.countsInfo.length>0">
<div style="font-weight: 700;color:#999">最大数量:{{ scope.row.countsInfo[0].max_total }}</div>
<div v-for="(item,index) in scope.row.countsInfo" :key="index" style="display: flex;">
<div style="font-weight:700;width: 50px;text-align: right;margin-right: 8px">{{ item.name
<div>
<div class="head">
<el-row>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.department_id" placeholder="选择科室"
style="margin-left: 8px;width: 150px;">
<el-option v-for="(item,index) in EnableDepartmentList" :key="index"
:label="item.department_name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.resources_id" placeholder="选择资源"
style="margin-left: 8px;width: 150px;">
<el-option v-for="(item,index) in enableResourceList" :key="index"
:label="item.department_resources_name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.device_id" placeholder="选择服务组"
style="margin-left: 8px;width: 150px;">
<el-option v-for="(item,index) in EnableDeviceList" :key="index" :label="item.device_name"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.xingqi" placeholder="星期"
style="margin-left: 8px;width: 150px;">
<el-option v-for="(item,index) in xingqi" :key="index" :label="item.label"
:value="item.label" />
</el-select>
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.status" placeholder="状态"
style="margin-left: 8px;width: 150px;">
<el-option label="正常" value="1" />
<el-option label="关闭" value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-date-picker style="margin-left: 8px; width: 300px" v-model="searchInfo.dateRange"
type="daterange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间"
value-format="YYYY-MM-DD" />
</el-form-item>
<el-button @click="GetList()" style="margin-left: 10px;">搜索</el-button>
<el-button type="danger" @click="Del()" style="margin-left: 10px;">删除</el-button>
</el-row>
</div>
<el-table :data="tableData" style="width: 100%;" row-key="id" v-loading="loading"
@selection-change="handleSelectionChange">
<el-table-column type="selection" />
<el-table-column prop="id" label="Id" />
<el-table-column prop="date" label="日期">
<template #default="scope">
<span>{{ scope.row.date.substring(0, 10) }}</span>
</template>
</el-table-column>
<el-table-column prop="weekname" label="星期" />
<el-table-column prop="resources_id" label="" v-if="false" />
<el-table-column prop="department_resources_name" label="资源" />
<el-table-column prop="" label="服务组" show-overflow-tooltip>
<template #default="scope">
<div v-if="scope.row.devices.length>0">
<div v-for="(item,index) in scope.row.devices" :key="index"
:class="(item.status==1 && item.is_del==0) ? '':'hongzi'">{{ item.device_name }}
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="period_name" label="时段" />
<el-table-column prop="begin_time" label="开始时间" />
<el-table-column prop="end_time" label="结束时间" />
<el-table-column prop="end_reservation_time" label="截止时间" />
<el-table-column prop="" label="类型数量" show-overflow-tooltip width="250">
<template #default="scope">
<div v-if="scope.row.countsInfo.length>0">
<div style="font-weight: 700;color:#999">最大数量:{{ scope.row.countsInfo[0].max_total }}</div>
<div v-for="(item,index) in scope.row.countsInfo" :key="index" style="display: flex;">
<div style="font-weight:700;width: 50px;text-align: right;margin-right: 8px">{{ item.name
}}
</div>
<div>:{{ item.count }} 已用: <span
style="font-weight: 700;color:#f5a96c">{{ item.used_count }}</span>
:{{ Number(item.count - item.used_count) }}
</div>
</div>
</div>
</template>
</el-table-column>
<!-- <el-table-column prop="time_unit" label="可用时长" width="80" />-->
<el-table-column prop="roster_status" label="状态" >
<template #default="scope">
<el-tag v-if="scope.row.status === 1" class="ml-2" type="success"></el-tag>
<el-tag v-if="scope.row.status === 0" class="ml-2" type="danger"></el-tag>
</template>
</el-table-column>
</div>
<div>:{{ item.count }} 已用: <span @click="GetMingXi(scope.row,item.appointment_type_id)"
class="yiyong">{{ item.used_count }}</span>
:{{ Number(item.count - item.used_count) }}
</div>
</div>
</div>
</template>
</el-table-column>
<!-- <el-table-column prop="time_unit" label="可用时长" width="80" />-->
<el-table-column prop="roster_status" label="状态">
<template #default="scope">
<el-tag v-if="scope.row.status === 1" class="ml-2" type="success"></el-tag>
<el-tag v-if="scope.row.status === 0" class="ml-2" type="danger"></el-tag>
</template>
</el-table-column>
<el-table-column prop="" label="操作" >
<template #default="scope">
<el-button type="primary" @click="getDetail(scope.row.id)" size="small" style="margin-left: 10px;">
修改
</el-button>
</template>
</el-table-column>
</el-table>
<div class="page">
<el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize"
:page-sizes="[15, 50, 100, 200]" layout="total,sizes, prev, pager, next" :total="total"
@size-change="PageSizeChange" @current-change="PageCurrentChange" />
</div>
<!-- 弹窗修改框-->
<el-dialog v-model="PlanDetailDialogVisible" title="修改" width="40%">
<div v-loading="loading">
<el-form v-if="PlanDetaiInfo" label-width="100px" style="padding-right: 40px;">
<el-form-item label="日期:">
{{ PlanDetaiInfo.date }}
</el-form-item>
<el-form-item label="星期:">
{{ PlanDetaiInfo.weekname }}
</el-form-item>
<el-form-item label="科室:">
{{ PlanDetaiInfo.department_name }}
</el-form-item>
<el-form-item label="资源:">
{{ PlanDetaiInfo.resources_name }}
</el-form-item>
<el-form-item label="服务组:">
<el-tag v-for="(item,index) in PlanDetaiInfo.devices" :key="index"
:type="(item.status===1 && item.is_del===0)?'':'danger'" style="margin-left: 8px">
{{ item.device_name }}
</el-tag>
</el-form-item>
<el-form-item label="病人类型:">
<el-checkbox-group disabled v-model="PlanDetaiInfo.patientType">
<el-checkbox label="0">住院</el-checkbox>
<el-checkbox label="1">门诊</el-checkbox>
<el-checkbox label="2">急诊</el-checkbox>
<el-checkbox label="3">体检</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="时间段:">
开始时间<span
style="font-weight: 700;display: inline-block;margin-right: 8px">{{ PlanDetaiInfo.begin_time
<el-table-column prop="" label="操作">
<template #default="scope">
<el-button type="primary" @click="getDetail(scope.row.id)" size="small" style="margin-left: 10px;">
修改
</el-button>
</template>
</el-table-column>
</el-table>
<div class="page">
<el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize"
:page-sizes="[15, 50, 100, 200]" layout="total,sizes, prev, pager, next" :total="total"
@size-change="PageSizeChange" @current-change="PageCurrentChange" />
</div>
<!-- 弹窗修改框-->
<el-dialog v-model="PlanDetailDialogVisible" title="修改" width="40%">
<div v-loading="loading">
<el-form v-if="PlanDetaiInfo" label-width="100px" style="padding-right: 40px;">
<el-form-item label="日期:">
{{ PlanDetaiInfo.date }}
</el-form-item>
<el-form-item label="星期:">
{{ PlanDetaiInfo.weekname }}
</el-form-item>
<el-form-item label="科室:">
{{ PlanDetaiInfo.department_name }}
</el-form-item>
<el-form-item label="资源:">
{{ PlanDetaiInfo.resources_name }}
</el-form-item>
<el-form-item label="服务组:">
<el-tag v-for="(item,index) in PlanDetaiInfo.devices" :key="index"
:type="(item.status===1 && item.is_del===0)?'':'danger'" style="margin-left: 8px">
{{ item.device_name }}
</el-tag>
</el-form-item>
<el-form-item label="病人类型:">
<el-checkbox-group disabled v-model="PlanDetaiInfo.patientType">
<el-checkbox label="0">住院</el-checkbox>
<el-checkbox label="1">门诊</el-checkbox>
<el-checkbox label="2">急诊</el-checkbox>
<el-checkbox label="3">体检</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="时间段:">
开始时间<span style="font-weight: 700;display: inline-block;margin-right: 8px">{{ PlanDetaiInfo.begin_time
}} </span> 结束时间<span
style="font-weight: 700;display: inline-block;margin-right: 8px">{{ PlanDetaiInfo.end_time }} </span>
停止预约时间<span style="font-weight: 700">{{ PlanDetaiInfo.end_reservation_time }}</span>
</el-form-item>
<el-form-item label="渠道名额:" v-if="PlanDetaiInfo.coutsInfo">
<div style="margin-right: 16px">
<div>当日总量</div>
<div class="qudao_k_input">
<el-input @input="MaxCountChange" type="number" v-model="PlanDetaiInfo.max_total"
:min="1"
placeholder="0"
oninput="value=value.replace(/^0|[^0-9]/g, '')" />
</div>
<div style="font-size: 12px;color: #999">设置渠道比例可自动分配</div>
</div>
<div>
<div class="qudao_k" v-for="(item,index) in PlanDetaiInfo.coutsInfo" :key="index">
<div style="width: 50px">{{ item.name }}</div>
<div class="qudao_k_input">
<el-input type="number" v-model="PlanDetaiInfo.coutsInfo[index].count" :min="1"
placeholder="0"
oninput="value=value.replace(/^0|[^0-9]/g, '')" />
</div>
</div>
</div>
</el-form-item>
<el-form-item label="状态:">
<el-switch v-model="PlanDetaiInfo.status" size="large" active-text="" inactive-text=""
:active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item label="添加时间:">
{{ PlanDetaiInfo.created_at }}
</el-form-item>
</el-form>
</div>
<template #footer>
style="font-weight: 700;display: inline-block;margin-right: 8px">{{ PlanDetaiInfo.end_time }}
</span>
停止预约时间<span style="font-weight: 700">{{ PlanDetaiInfo.end_reservation_time }}</span>
</el-form-item>
<el-form-item label="渠道名额:" v-if="PlanDetaiInfo.coutsInfo">
<div style="margin-right: 16px">
<div>当日总量</div>
<div class="qudao_k_input">
<el-input @input="MaxCountChange" type="number" v-model="PlanDetaiInfo.max_total"
:min="1" placeholder="0" oninput="value=value.replace(/^0|[^0-9]/g, '')" />
</div>
<div style="font-size: 12px;color: #999">设置渠道比例可自动分配</div>
</div>
<div>
<div class="qudao_k" v-for="(item,index) in PlanDetaiInfo.coutsInfo" :key="index">
<div style="width: 50px">{{ item.name }}</div>
<div class="qudao_k_input">
<el-input type="number" v-model="PlanDetaiInfo.coutsInfo[index].count" :min="1"
placeholder="0" oninput="value=value.replace(/^0|[^0-9]/g, '')" />
</div>
</div>
</div>
</el-form-item>
<el-form-item label="状态:">
<el-switch v-model="PlanDetaiInfo.status" size="large" active-text="" inactive-text=""
:active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item label="添加时间:">
{{ PlanDetaiInfo.created_at }}
</el-form-item>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="PlanDetailDialogVisible = false">取消</el-button>
<el-button type="primary" @click="SavePlanAction">
确定
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
</el-dialog>
<el-dialog v-model="MingXiDialogVisible" title="预约明细" width="50%">
<div>
<div style="text-align: center;font-size: 16px; margin-top: -30px;margin-bottom: 10px;">{{selectedPlanRow.department_resources_name}}
<span v-for="(item,index) in selectedPlanRow.devices" :key="index"
:class="(item.status==1 && item.is_del==0) ? '':'hongzi'">{{ item.device_name }}
</span>
</div>
<el-form-item label="渠道">
<el-select :filterable="true" clearable v-model="selectecQuDaoid" @change="GetMingXi(selectedPlanRow,selectecQuDaoid)" placeholder="选择渠道"
style="margin-left: 8px;width: 150px;">
<el-option v-for="(item1,index1) in selectedPlanRow.countsInfo" :key="index1"
:label="item1.name" :value="item1.appointment_type_id" />
</el-select>
</el-form-item>
<el-table :data="MingXiList" style="width: 100%;" row-key="id" v-loading="MingXiLoading">
<el-table-column prop="list_status" label="状态" width="100">
<template #default="scope">
<el-tag v-if="scope.row.list_status===0" class="ml-2" type="info"></el-tag>
<el-tag v-if="scope.row.list_status===1" class="ml-2" type="success"></el-tag>
<el-tag v-if="scope.row.list_status===2" class="ml-2"></el-tag>
<el-tag v-if="scope.row.list_status===3" class="ml-2" type="warning"></el-tag>
</template>
</el-table-column>
<el-table-column prop="user_name" label="姓名" />
<el-table-column prop="user_phone" label="电话" />
<el-table-column prop="reg_num" label="登记号" />
<el-table-column prop="reservation_department" label="申请科室" />
<el-table-column prop="entrust" label="项目" />
</el-table>
</div>
</el-dialog>
</div>
</template>
<script setup>
import {
ref,
onMounted
} from 'vue'
import {
PlanListGetList,
GetEnableDepartmentList,
GetEnableDeviceList,
TimePeriodGetEnableList,
DepartmentResourceGetEnableList,
PlanDetailChangeInfo,
PlanListGetDetail,
PlanDetailPlanListDel
} from '@/api/api.js'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
ref,
onMounted
} from 'vue'
import {
PlanListGetList,
GetEnableDepartmentList,
GetEnableDeviceList,
TimePeriodGetEnableList,
DepartmentResourceGetEnableList,
PlanDetailChangeInfo,
PlanListGetDetail,
PlanDetailPlanListDel,
GetPlanUsedList
} from '@/api/api.js'
import {
ElMessage,
ElMessageBox
} from 'element-plus'
let loading = ref(false)
let tableData = ref([])
let currentPage = ref(1) //
let pageSize = ref(15) //
let total = 0 //
const PageSizeChange = (e) => { //
pageSize.value = e
GetList()
}
const PageCurrentChange = (e) => { //
currentPage.value = e
GetList()
}
let tableSelected = ref([])
const handleSelectionChange = (e) => {
tableSelected.value = e
}
let searchInfo = ref({
department_id: null,
resources_id: null,
device_id: null,
xingqi: null,
status: null,
dateRange: []
})
let PlanDetailDialogVisible = ref(false)
const GetList = () => {
PlanListGetList({
page: currentPage.value,
pageSize: pageSize.value,
searchInfo: searchInfo.value
}).then(res => {
tableData.value = res.data.list
total = res.data.count
})
}
let loading = ref(false)
let tableData = ref([])
let currentPage = ref(1) //
let pageSize = ref(15) //
let total = 0 //
const PageSizeChange = (e) => { //
pageSize.value = e
GetList()
}
const PageCurrentChange = (e) => { //
currentPage.value = e
GetList()
}
let tableSelected = ref([])
const handleSelectionChange = (e) => {
tableSelected.value = e
}
let searchInfo = ref({
department_id: null,
resources_id: null,
device_id: null,
xingqi: null,
status: null,
dateRange: []
})
let PlanDetailDialogVisible = ref(false)
const GetList = () => {
PlanListGetList({
page: currentPage.value,
pageSize: pageSize.value,
searchInfo: searchInfo.value
}).then(res => {
tableData.value = res.data.list
total = res.data.count
})
}
let xingqi = ref([{
label: '星期一',
value: 1
}, {
label: '星期二',
value: 2
}, {
label: '星期三',
value: 3
}, {
label: '星期四',
value: 4
}, {
label: '星期五',
value: 5
}, {
label: '星期六',
value: 6
}, {
label: '星期日',
value: 7
}])
//
let EnableDeviceList = ref([])
const GetEnableDeviceListFunc = () => {
loading.value = true
GetEnableDeviceList().then(res => {
loading.value = false
if (res.status) {
EnableDeviceList.value = res.data
} else {
ElMessage.error(res.msg)
}
let xingqi = ref([{
label: '星期一',
value: 1
}, {
label: '星期二',
value: 2
}, {
label: '星期三',
value: 3
}, {
label: '星期四',
value: 4
}, {
label: '星期五',
value: 5
}, {
label: '星期六',
value: 6
}, {
label: '星期日',
value: 7
}])
//
let EnableDeviceList = ref([])
const GetEnableDeviceListFunc = () => {
loading.value = true
GetEnableDeviceList().then(res => {
loading.value = false
if (res.status) {
EnableDeviceList.value = res.data
} else {
ElMessage.error(res.msg)
}
})
}
let EnableDepartmentList = ref([])
const GetDepartmentEnableList = () => {
loading.value = true
GetEnableDepartmentList({}).then(res => {
loading.value = false
if (res.status) {
EnableDepartmentList.value = res.data.list
} else {
ElMessage.error(res.msg)
}
})
}
let EnableDepartmentList = ref([])
const GetDepartmentEnableList = () => {
loading.value = true
GetEnableDepartmentList({}).then(res => {
loading.value = false
if (res.status) {
EnableDepartmentList.value = res.data.list
} else {
ElMessage.error(res.msg)
}
})
}
// //
// let TimePeriodList = ref([])
// const GetEnableTimePeriod = () => {
// loading.value = true
// TimePeriodGetEnableList().then(res => {
// loading.value = false
// if (res.status) {
// TimePeriodList.value = res.data
// } else {
// ElMessage.error(res.msg)
// }
//
// })
// }
//
let enableResourceList = ref([])
const getEnableResource = () => {
loading.value = true
DepartmentResourceGetEnableList().then(res => {
loading.value = false
if (res.status) {
enableResourceList.value = res.data
} else {
ElMessage.error(res.msg)
}
})
}
// //
// let TimePeriodList = ref([])
// const GetEnableTimePeriod = () => {
// loading.value = true
// TimePeriodGetEnableList().then(res => {
// loading.value = false
// if (res.status) {
// TimePeriodList.value = res.data
// } else {
// ElMessage.error(res.msg)
// }
//
// })
// }
//
let enableResourceList = ref([])
const getEnableResource = () => {
loading.value = true
DepartmentResourceGetEnableList().then(res => {
loading.value = false
if (res.status) {
enableResourceList.value = res.data
} else {
ElMessage.error(res.msg)
}
})
}
//
let PlanDetaiInfo = ref('')
const getDetail = (id) => {
PlanDetailDialogVisible.value = true
loading.value = true
PlanListGetDetail({
id: id
}).then(res => {
loading.value = false
if (res.status) {
PlanDetaiInfo.value = res.data
} else {
ElMessage.error(res.msg)
}
})
}
//
let PlanDetaiInfo = ref('')
const getDetail = (id) => {
PlanDetailDialogVisible.value = true
loading.value = true
PlanListGetDetail({ id: id }).then(res => {
loading.value = false
if (res.status) {
PlanDetaiInfo.value = res.data
} else {
ElMessage.error(res.msg)
}
})
}
//
const MaxCountChange = (e) => {
console.log(e)
if (e === '' || e == null || e === 0) {
PlanDetaiInfo.value.max_total = 0
}
let temp = 0
let qudao_count = PlanDetaiInfo.value.coutsInfo.length
})
}
//
const MaxCountChange = (e) => {
console.log(e)
if (e === '' || e == null || e === 0) {
PlanDetaiInfo.value.max_total = 0
}
let temp = 0
let qudao_count = PlanDetaiInfo.value.coutsInfo.length
for (let i = 0; i < qudao_count; i++) {
if (PlanDetaiInfo.value.coutsInfo[i].ratio === 0) continue
PlanDetaiInfo.value.coutsInfo[i].count = Math.round(PlanDetaiInfo.value.max_total * (PlanDetaiInfo.value
.coutsInfo[i].ratio / 100))
temp = temp + PlanDetaiInfo.value.coutsInfo[i].count
//1
if (i === qudao_count - 1 && temp !== PlanDetaiInfo.value.max_total) {
PlanDetaiInfo.value.coutsInfo[i].count = PlanDetaiInfo.value.coutsInfo[i].count - (temp - PlanDetaiInfo
.value.max_total)
}
}
}
//
const SavePlanAction = () => {
let tempCount = 0
PlanDetaiInfo.value.coutsInfo.forEach((item) => {
tempCount = tempCount + Number(item.count)
})
if (tempCount !== Number(PlanDetaiInfo.value.max_total)) {
ElMessage.error('各个渠道数量之和与当日总量不符')
return false
}
loading.value = true
PlanDetailChangeInfo({
PlanDetaiInfo: PlanDetaiInfo.value
}).then(res => {
loading.value = false
if (res.status) {
PlanDetailDialogVisible.value = false
GetList()
} else {
ElMessage.error(res.msg)
}
for (let i = 0; i < qudao_count; i++) {
if (PlanDetaiInfo.value.coutsInfo[i].ratio === 0) continue
PlanDetaiInfo.value.coutsInfo[i].count = Math.round(PlanDetaiInfo.value.max_total * (PlanDetaiInfo.value.coutsInfo[i].ratio / 100))
temp = temp + PlanDetaiInfo.value.coutsInfo[i].count
//1
if (i === qudao_count - 1 && temp !== PlanDetaiInfo.value.max_total) {
PlanDetaiInfo.value.coutsInfo[i].count = PlanDetaiInfo.value.coutsInfo[i].count - (temp - PlanDetaiInfo.value.max_total)
}
}
}
//
const SavePlanAction = () => {
let tempCount = 0
PlanDetaiInfo.value.coutsInfo.forEach((item) => {
tempCount = tempCount + Number(item.count)
})
if (tempCount !== Number(PlanDetaiInfo.value.max_total)) {
ElMessage.error('各个渠道数量之和与当日总量不符')
return false
}
loading.value = true
PlanDetailChangeInfo({ PlanDetaiInfo: PlanDetaiInfo.value }).then(res => {
loading.value = false
if (res.status) {
PlanDetailDialogVisible.value = false
GetList()
} else {
ElMessage.error(res.msg)
}
})
}
const Del = () => {
if (tableSelected.value.length == 0) {
ElMessage.error("请至少勾选1条记录")
return false
}
let ids = []
tableSelected.value.map((item) => {
ids.push(item.id)
})
ElMessageBox.confirm(
'确定删除吗?',
'提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
loading.value = true
PlanDetailPlanListDel({
ids: ids
}).then(res => {
loading.value = false
if (res.status) {
ElMessage({
message: res.msg,
type: 'success',
})
GetList()
} else {
ElMessage.error(res.msg)
}
})
})
}
let MingXiDialogVisible = ref(false);
let MingXiLoading = ref(false)
let MingXiList = ref(null);
let selectedPlanRow = ref(null);
let selectecQuDaoid =ref(null);
const GetMingXi = (row, typeid) => {
selectecQuDaoid.value=typeid
selectedPlanRow.value = row
MingXiDialogVisible.value = true
MingXiLoading.value = true
GetPlanUsedList({
planid: row.id,
qudaoid: typeid
}).then(res => {
MingXiLoading.value = false
if (res.status) {
MingXiList.value = res.data
} else {
ElMessage.error(res.msg)
}
})
}
const Del=()=>{
if(tableSelected.value.length==0){
ElMessage.error("请至少勾选1条记录")
return false
}
let ids=[]
tableSelected.value.map((item)=>{
ids.push(item.id)
})
ElMessageBox.confirm(
'确定删除吗?',
'提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
loading.value = true
PlanDetailPlanListDel({ ids: ids}).then(res => {
loading.value = false
if (res.status) {
ElMessage({
message: res.msg,
type: 'success',
})
GetList()
} else {
ElMessage.error(res.msg)
}
})
})
}
onMounted(() => {
GetList()
GetDepartmentEnableList()
getEnableResource()
GetEnableDeviceListFunc()
})
})
}
onMounted(() => {
GetList()
GetDepartmentEnableList()
getEnableResource()
GetEnableDeviceListFunc()
})
</script>
<style scoped>
.type_count {
display: flex;
}
.type_count {
display: flex;
}
.type_count div {
white-space: nowrap;
margin-right: 10px;
}
.qudao_k {
display: flex;
}
.type_count div {
white-space: nowrap;
margin-right: 10px;
}
.qudao_k_input {
width: 150px;
}
.qudao_k {
display: flex;
}
.hongzi {
color: #b25252;
}
.qudao_k_input {
width: 150px;
}
.yiyong {
font-weight: 700;
color: #f5a96c;
cursor: pointer;
}
.hongzi {
color: #b25252;
}
.yiyong:hover {
color: #666;
}
</style>

File diff suppressed because it is too large Load Diff

@ -1,19 +1,32 @@
<template>
<div style="display: flex" v-loading="loading">
<div style="width: 400px;margin-right: 40px">
<el-form :model="ratioInfo" label-width="auto" style="max-width: 600px">
<el-form-item v-for="(item,index) in ratioInfo" :key="index" :label="item.name">
<el-input size="large" type="number" min="0" max="100" v-model="ratioInfo[index].ratio"
style="margin-left: 10px;" />
</el-form-item>
</el-form>
</div>
<div style="display: flex;justify-content: center; align-items: center;">
<el-button type="primary" @click="Save" style="height: 70px;width: 100px">
确定
</el-button>
</div>
</div>
<div>
<div style="margin: 12px;color:#999">
设置说明此功能为各个预约渠道设置默认数量百分比用于为预约计划按比例自动分配数量此次设置各个渠道的数值总数应为100如果不想给某个渠道分配可设置为0
</div>
<div style="display: flex" v-loading="loading">
<div style="width: 400px;margin-right: 40px">
<el-form :model="ratioInfo" label-width="auto" style="max-width: 600px">
<el-form-item v-for="(item,index) in ratioInfo" :key="index" :label="item.name">
<div style="display: flex;">
<el-input size="large" type="number" min="0" max="100" v-model="ratioInfo[index].ratio"
style="margin-left: 10px;width: 250px;" />
<div style="margin-left: 10px;">%</div>
</div>
</el-form-item>
</el-form>
</div>
<div style="display: flex;justify-content: center; align-items: center;">
<el-button type="primary" @click="Save" style="height: 70px;width: 100px">
确定
</el-button>
</div>
</div>
</div>
</template>
<script setup>
import {

@ -46,14 +46,14 @@
</el-form-item>
<el-form-item label="时间段:">
<el-time-picker v-model="PeriodInfo.timeRange" value-format='HH:mm' is-range range-separator=""
start-placeholder="开始时间" end-placeholder="结束时间" />
start-placeholder="开始时间" end-placeholder="结束时间" @change="changeTimeRange()" />
</el-form-item>
<el-form-item label="预约截止时间:">
<el-time-picker v-model="PeriodInfo.period_deadline" value-format='HH:mm' placeholder="预约截止时间" />
</el-form-item>
<el-form-item label="状态:">
<el-switch v-model="PeriodInfo.period_status" size="large" active-text="" inactive-text=""
:active-value="1" :inactive-value="0" />
active-value="1" inactive-value="0" />
</el-form-item>
</el-form>
<template #footer>
@ -154,18 +154,29 @@
period_begin_time:'',
period_end_time:'',
period_deadline:'',
period_status:1,
period_status:"1",
timeRange:[]
});
const Edit=(row)=>{
let data=row
dialogVisible.value=true
PeriodInfo.value=data
PeriodInfo.value.timeRange=[PeriodInfo.value.period_begin_time,PeriodInfo.value.period_end_time]
PeriodInfo.value.period_status=data.period_status.toString()
console.log(PeriodInfo.value)
}
const Add=()=>{
dialogVisible.value=true
PeriodInfo.value={id:0};
PeriodInfo.value={
id:0,
period_name:'',
period_begin_time:'',
period_end_time:'',
period_deadline:'',
period_status:"1",
timeRange:[]
}
}
const Del = (id) => {
@ -193,6 +204,13 @@
})
})
}
//
const changeTimeRange=()=>{
PeriodInfo.value.period_deadline=PeriodInfo.value.timeRange[1]
}
onMounted(()=>{
GetList()

@ -6,7 +6,7 @@
<el-col :span="9" class="left">
</el-col>
<el-col :span="15" class="right">
<el-col :span="15" class="right" v-loading="loading">
<div class="right_top">
<div>
<el-switch v-model="isDark" inline-prompt active-color="var(--el-fill-color-dark)"
@ -19,10 +19,10 @@
<span style="font-size: 22px;">登录您的账户</span>
</el-form-item>
<el-form-item>
<el-input v-model.number="username" :prefix-icon="User" placeholder="用户名" size="large" />
<el-input v-model.number="username" ref="usernameRef" @keyup.enter="focusNextTo()" :prefix-icon="User" placeholder="用户名" size="large" />
</el-form-item>
<el-form-item>
<el-input v-model="pwd" type="password" autocomplete="off" placeholder="密码" size="large"
<el-input v-model="pwd" type="password" ref="passwordRef" @keyup.enter="login()" autocomplete="off" placeholder="密码" size="large"
:prefix-icon="Lock" />
</el-form-item>
<el-form-item>
@ -47,7 +47,7 @@
ElMessage
} from 'element-plus'
import {
ref
ref,nextTick,onMounted
} from 'vue'
import {
Lock,
@ -64,7 +64,7 @@
const isDark = useDark()
const toggleDark = () => useToggle(isDark)
let loading=ref(false);
let username = ref('')
let pwd = ref('')
@ -74,9 +74,10 @@
username: username.value,
password: pwd.value,
}
loading.value=true
//
Login(data).then(res => {
loading.value=false
if (res.data.status == 'ok') {
sessionStorage.setItem('token', res.data.token);
sessionStorage.setItem('refreshToken', res.data.refresh_token);
@ -93,8 +94,16 @@
}
let usernameRef=ref(null);
let passwordRef=ref(null);
const focusNextTo=()=>{
passwordRef.value.focus()
}
onMounted(()=>{
nextTick(()=>{
usernameRef.value.focus()
})
})
</script>

@ -1,19 +1,34 @@
<template>
<div>
<el-row style="margin: 10px auto;">
<el-button type="primary" @click="add()"></el-button>
<!-- <el-button type="danger">删除</el-button> -->
</el-row>
<el-table :data="tableData" style="width: 100%;" row-key="id">
<div class="head">
<el-row>
<el-form-item>
<el-input v-model="searchInfo.cname" placeholder="请输入用户名" style="margin-left: 10px;" />
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.status" placeholder="所有状态"
style="margin-left: 10px;">
<el-option label="正常" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
<el-button @click="GetUserList()" style="margin-left: 10px;">查询</el-button>
<el-button type="primary" @click="add()" style="margin-left: 10px;">新建用户</el-button>
</el-row>
</div>
<el-table :data="tableData" style="width: 100%;" row-key="id">
<el-table-column prop="id" label="Id" width="100" />
<el-table-column prop="cname" label="名称" />
<el-table-column prop="uname" label="用户名" />
<el-table-column prop="group_name" label="分组" />
<el-table-column prop="department_name" label="科室" />
<el-table-column prop="status" label="状态">
<template #default="scope">
<el-tag v-if="scope.row.status==1" class="ml-2" type="success"></el-tag>
<el-tag v-if="scope.row.status==0" class="ml-2" type="danger"></el-tag>
</template>
<template #default="scope">
<el-tag v-if="scope.row.status==1" class="ml-2" type="success"></el-tag>
<el-tag v-if="scope.row.status==0" class="ml-2" type="danger"></el-tag>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间" />
<el-table-column label="操作" width="100">
@ -31,7 +46,7 @@
<el-dialog v-model="dialogVisible" title="用户" width="30%">
<el-form :model="UserInfo" label-width="50px" v-loading="loading">
<el-form-item label="分组">
<el-select v-model="UserInfo.groupId" placeholder="请选择分组">
<el-option v-for="(item,index) in groupList" :key="index" :label="item.group_name"
@ -42,12 +57,15 @@
<el-input v-model="UserInfo.cname" />
</el-form-item>
<el-form-item label="账号">
<el-input v-model="UserInfo.uname" disabled/>
<el-input v-model="UserInfo.uname" :disabled="usernameDisabled" />
</el-form-item>
<el-form-item label="状态">
<el-switch v-model="UserInfo.status" size="large" active-text="" inactive-text=""
:active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item>
<el-button @click="resetPwdClick()"></el-button>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
@ -58,13 +76,33 @@
</span>
</template>
</el-dialog>
<el-dialog v-model="resetPwdDialogShow" title="重置密码" width="30%">
<el-form :model="UserInfo" label-width="100px" v-loading="loading">
<el-form-item label="重置密码">
<div style="display: flex;">
<el-input v-model="Password" />
<el-button :icon="Refresh" @click="random()"></el-button>
</div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="resetPwdDialogShow = false">取消</el-button>
<el-button type="primary" @click="resetPwdSave()">
确定
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {
ref,
onMounted
onMounted,
watch,
} from 'vue'
import {
ElMessage
@ -73,11 +111,21 @@
getGroupList,
getAdminUserList,
SaveSystemUserInfo,
GetSystemUserDetail
GetSystemUserDetail,
resetPwd
} from '@/api/api.js'
import {
Edit
Edit,
Refresh
} from '@element-plus/icons-vue'
import {
useRoute,
useRouter
} from "vue-router"
const route = useRoute()
const router = useRouter()
let loading = ref(false)
let saveType = ref('save')
let tableData = ref([])
@ -93,8 +141,20 @@
id: 0,
status: 1,
})
let searchInfo = ref({
status: null,
cname: '',
departmentid: null
})
let usernameDisabled = ref(false);
const GetUserList = () => {
getAdminUserList({
...searchInfo.value,
page: currentPage.value,
pageSize: pageSize.value
}).then(res => {
@ -134,16 +194,18 @@
})
}
const add = (id1 = '') => {
usernameDisabled.value = false
dialogVisible.value = true
UserInfo.value = {
groupId: '',
cname: '',
uname: '',
id:id1,
id: id1,
status: 1,
}
GetGroupList()
if (id1 > 0) {
usernameDisabled.value = true
GetSystemUserDetail({
id: id1
}).then(res => {
@ -156,9 +218,52 @@
}
}
watch(
() => route.query.departmentId,
(newDepartmentId, oldDepartmentId) => {
// departmentId
console.log(`Department ID changed from ${oldDepartmentId} to ${newDepartmentId}`);
if (route.query.departmentId) {
searchInfo.value.departmentid = Number(route.query.departmentId)
} else {
searchInfo.value.departmentid = null
}
GetUserList() // departmentId
}, {
immediate: true
} // immediate: true
);
let resetPwdDialogShow = ref(false);
let Password = ref('');
const resetPwdClick = () => {
resetPwdDialogShow.value = true
}
const random = () => {
let password = '';
for (let i = 0; i < 6; i++) {
password += Math.floor(Math.random() * 10); // 09
}
Password.value = password
}
const resetPwdSave = () => {
resetPwd({
userid: UserInfo.value.id,
password:Password.value,
}).then(res => {
if(res.status){
ElMessage({
message: '修改成功',
type: 'success',
})
resetPwdDialogShow.value=false
Password.value=''
}else{
ElMessage.error(res.msg)
}
})
}
onMounted(() => {
GetUserList()
})
</script>
@ -168,6 +273,4 @@
justify-content: flex-end;
margin-top: 10px;
}
</style>
</style>

@ -80,10 +80,15 @@
</el-dialog>
<el-dialog v-model="ItemDialogVisible" title="编辑项目" width="40%">
<div class="row"><span class="title">医嘱名称</span>{{selectedItemInfo.item_name}}</div>
<div class="row"><span class="title">预约方式</span><el-select style=" width: 200px;" clearable
<div class="row"><span class="title">预约方式</span>
<!-- <el-select style=" width: 200px;" clearable
v-model="selectedItemInfo.reservation_method" placeholder="预约方式">
<el-option v-for="(item, index) in yuyueType" :key="index" :label="item.name" :value="item.id" />
</el-select></div>
</el-select> -->
<el-checkbox-group v-if="yuyueType" v-model="selectedItemInfo.reservation_method">
<el-checkbox v-for="(item, index) in yuyueType" :label="item.id" :value="item.id" :key="index">{{item.name}}</el-checkbox>
</el-checkbox-group>
</div>
<div class="row"><span class="title">空腹</span><el-select :filterable="true" clearable
v-model="selectedItemInfo.limosis" placeholder="是否空腹" style=" width: 100px;">
<el-option label="否" :value="0" />
@ -94,7 +99,7 @@
<div class="row"><span class="title">检查时间</span><el-input v-model="selectedItemInfo.check_time"
placeholder="请输入此项检查的时长" style="width: 200px;" /></div>
<div class="row"><span class="title">开始预约时间</span><el-input v-model="selectedItemInfo.check_begin_time"
placeholder="请输入此项检查的时长" style="width: 200px;" /></div>
placeholder="开医嘱后多久能开始预约" style="width: 200px;" /><div style="margin-left: 4px;">开医嘱后多久能开始预约,单位分钟</div></div>
<div class="row"><span class="title">检查须知</span><el-input v-model="selectedItemInfo.check_notice"
@ -142,6 +147,7 @@
</template>
<script setup>
import {
ref,
onMounted
@ -175,7 +181,7 @@
limosis: '',
reservation_method: '',
check_time: '',
check_begin_time: '',
check_begin_time:'',
check_notice: ''
})
//list
@ -197,6 +203,7 @@
})
}
//
let tableData = ref([])
let currentPage = ref(1) //
@ -211,7 +218,13 @@
}).then(res => {
loading.value = false
if (res.status) {
tableData.value = res.data.list
let list =res.data.list;
// list.forEach(function(v,i){
// if(v.reservation_method){
// list[i].reservation_method=v.reservation_method.split(",")
// }
// })
tableData.value = list
total = res.data.count
} else {
ElMessage.error(res.msg)
@ -281,6 +294,9 @@
selectedItemInfo.value.limosis = row.limosis
selectedItemInfo.value.reservation_method = row.reservation_method
selectedItemInfo.value.check_time = row.check_time
if(row.check_begin_time=='' || row.check_begin_time==null){
row.check_begin_time=0
}
selectedItemInfo.value.check_begin_time = row.check_begin_time
selectedItemInfo.value.check_notice = row.check_notice
}
@ -297,7 +313,7 @@
})
}
//
const SaveItemInfoFunc = () => {
const SaveItemInfoFunc = () => {
SaveItemInfo({
Info: selectedItemInfo.value
}).then(res => {

@ -35,7 +35,7 @@
<template #content>
<div v-for="(item,index) in scope.row.user_list">{{index+1}}. {{item.cn_name}}</div>
</template>
<div style="color: #00aaff; font-size: 12px; cursor: pointer; ">
<div style="color: #00aaff; font-size: 12px; cursor: pointer;" @click="gotoUserList(scope.row)">
已关联{{scope.row.user_list.length}}</div>
</el-tooltip>
</div>
@ -293,6 +293,9 @@
})
}
const gotoUserList=(row)=>{
window.location.href = "./#/adminUserList?departmentId=" + row.id
}
onMounted(() => {
getGroup()
GetList()

@ -5,78 +5,69 @@
<iframe id="bdIframe" class="iframe" :key="iframeKey" :src="selectedUrl" scrolling="auto"></iframe>
</el-dialog>
<div class="head">
<el-row >
<el-row>
<el-form-item>
<el-date-picker style="margin-left: 8px; width: 300px"
v-model="searchInfo.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD"
/>
<el-date-picker style="margin-left: 8px; width: 300px" v-model="searchInfo.dateRange"
type="daterange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间"
value-format="YYYY-MM-DD" />
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.list_status" placeholder="状态"
style="margin-left: 8px;width: 150px;"
>
<el-option label="申请中" value="0" />
<el-option label="已预约" value="1" />
<el-option label="已报道" value="2" />
<el-option label="已结束" value="3" />
</el-select>
<el-select :filterable="true" clearable v-model="searchInfo.list_status" placeholder="状态"
style="margin-left: 8px;width: 150px;">
<el-option label="申请中" value="0" />
<el-option label="已预约" value="1" />
<el-option label="已报道" value="2" />
<el-option label="已结束" value="3" />
</el-select>
</el-form-item>
<el-form-item>
<el-select :filterable="true" clearable v-model="searchInfo.patient_type" placeholder="患者类型"
style="margin-left: 8px;width: 150px;"
>
<el-option label="住院" value="0" />
<el-option label="门诊" value="1" />
<el-option label="急诊" value="2" />
<el-option label="体检" value="3" />
</el-select>
<el-select :filterable="true" clearable v-model="searchInfo.patient_type" placeholder="患者类型"
style="margin-left: 8px;width: 150px;">
<el-option label="住院" value="0" />
<el-option label="门诊" value="1" />
<el-option label="急诊" value="2" />
<el-option label="体检" value="3" />
</el-select>
</el-form-item>
<el-form-item>
<el-select multiple :filterable="true" clearable v-model="searchInfo.resources" placeholder="资源"
style="margin-left: 8px;width: 250px;"
>
<!-- <el-option label="住院" value="0" />
<el-option label="门诊" value="1" />
<el-option label="急诊" value="2" />
<el-option label="体检" value="3" /> -->
</el-select>
<el-select multiple :filterable="true" clearable v-model="searchInfo.resources" placeholder="资源"
style="margin-left: 8px;width: 250px;">
<el-option v-for="(item,index) in enableResourceList" :key="index"
:label="item.department_resources_name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-select multiple :filterable="true" clearable v-model="searchInfo.services_group" placeholder="服务组"
style="margin-left: 8px;width: 150px;"
>
</el-select>
<el-select :filterable="true" clearable v-model="searchInfo.services_group" placeholder="服务组"
style="margin-left: 8px;width: 150px;">
<el-option v-for="(item,index) in EnableDeviceList" :key="index" :label="item.device_name"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-input v-model="searchInfo.reg_num" placeholder="登记号" style="width: 200px;margin-left: 8px;"/>
<el-input v-model="searchInfo.reg_num" placeholder="登记号" style="width: 200px;margin-left: 8px;" />
</el-form-item>
<el-form-item>
<el-input v-model="searchInfo.user_name" placeholder="患者姓名" style="width: 200px;margin-left: 8px;"/>
<el-input v-model="searchInfo.user_name" placeholder="患者姓名"
style="width: 200px;margin-left: 8px;" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="GetList()" style="margin-left: 10px;">查询</el-button>
</el-form-item>
</el-row>
<el-row style="margin: 0px 0px 8px 8px; border-top: 1px solid #ccc;padding-top: 8px">
<el-button type="success" @click="openIframe(1)"> </el-button>
<el-button type="danger" @click="cancel()"></el-button>
<el-button type="warning" @click="openIframe(2)"></el-button>
<el-button type="primary" >报到</el-button>
<el-button type="primary">报到</el-button>
</el-row>
</div>
<el-table :data="tableData" style="width: 100%;" row-key="id" v-loading="loading"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" />
<el-table-column prop="list_status" label="状态" width="100">
<el-table-column prop="list_status" label="状态" width="80">
<template #default="scope">
<el-tag v-if="scope.row.list_status===0" class="ml-2" type="info"></el-tag>
<el-tag v-if="scope.row.list_status===1" class="ml-2" type="success"></el-tag>
@ -86,15 +77,15 @@
</el-table-column>
<el-table-column prop="reg_num" label="登记号" width="100" />
<el-table-column prop="user_name" label="姓名" />
<el-table-column prop="user_sex" label="性别" width="100">
<el-table-column prop="user_sex" label="性别" width="60">
<template #default="scope">
<span v-if="scope.row.user_sex==1"></span>
<span v-if="scope.row.user_sex==2"></span>
</template>
</el-table-column>
<el-table-column prop="age" label="年龄" />
<el-table-column prop="entrust" label="医嘱" />
<el-table-column prop="is_pay" label="是否交费" width="100">
<el-table-column prop="age" label="年龄" width="115" />
<el-table-column prop="entrust" label="医嘱" width="200" />
<el-table-column prop="is_pay" label="是否交费" width="80">
<template #default="scope">
<span v-if="scope.row.is_pay==1"></span>
<span v-if="scope.row.is_pay==0"></span>
@ -108,13 +99,13 @@
</template>
</el-table-column>
<el-table-column prop="reservation_department" label="申请科室" width="120" />
<el-table-column prop="" label="医嘱时间" width="120">
<el-table-column prop="" label="医嘱时间" width="160">
<template #default="scope">
{{scope.row.entrust_date}} {{scope.row.entrust_time}}
</template>
</el-table-column>
<el-table-column prop="docotr" label="申请医生" width="120" />
<el-table-column prop="patient_type" label="病人类型" width="120">
<el-table-column prop="docotr" label="申请医生" width="80" />
<el-table-column prop="patient_type" label="病人类型" width="80">
<template #default="scope">
<span v-if="scope.row.patient_type==0"></span>
<span v-if="scope.row.patient_type==1"></span>
@ -124,15 +115,20 @@
</el-table-column>
<el-table-column prop="department_resources_name" label="预约资源" width="120" />
<el-table-column prop="user_phone" label="电话" width="120" />
<el-table-column prop="implement_department" label="执行科室" width="120" />
<!-- <el-table-column prop="implement_department" label="执行科室" width="120" /> -->
<el-table-column prop="devices" label="服务组">
<template #default="scope">
<span v-for="(item,index) in scope.row.devices" :key="index">
<el-tag v-if="item.status==1 && item.is_del==0" class="ml-2"
type="success">{{ item.device_name }}</el-tag>
<el-tag v-if="item.status==0 || item.is_del==1" class="ml-2"
type="danger">{{ item.device_name }}</el-tag>
</span>
<div style="white-space: nowrap;">
<span v-for="(item,index) in scope.row.devices" :key="index">
{{ item.device_name+ ' ' }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="department_resources_name" label="操作" width="120">
<template #default="scope">
<el-button @click="showLog(scope.row)" size="small">查看日志</el-button>
</template>
</el-table-column>
</el-table>
@ -141,6 +137,35 @@
:page-sizes="[15, 50, 100, 200]" layout="total,sizes, prev, pager, next" :total="total"
@size-change="PageSizeChange" @current-change="PageCurrentChange" />
</div>
<el-dialog v-model="LogShow" title="变更记录" width="50%">
<div>
<el-table :data="LogList" style="width: 100%;" row-key="id">
<el-table-column prop="list_status" label="状态" width="100">
<template #default="scope">
<el-tag v-if="scope.row.new_status==0" class="ml-2" type="info"></el-tag>
<el-tag v-if="scope.row.new_status==1" class="ml-2" type="success"></el-tag>
<el-tag v-if="scope.row.new_status==2" class="ml-2"></el-tag>
<el-tag v-if="scope.row.new_status==3" class="ml-2" type="warning"></el-tag>
</template>
</el-table-column>
<el-table-column prop="reg_num" label="登记号" />
<el-table-column prop="note" label="说明" />
<el-table-column prop="created_at" label="记录时间" />
<el-table-column prop="data" label="状态" width="100">
<template #default="scope">
<el-button @click="showLogJson(scope.row.data)" size="small">查看data</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-dialog>
<el-dialog v-model="LogDataShow" title="查看dataJson" width="40%">
<div style="word-break: break-all">
{{LogDataJson}}
</div>
</el-dialog>
</div>
</template>
@ -153,8 +178,11 @@
import {
GetMainList,
CancelYuYue
CancelYuYue,
GetEnableDeviceList,
DepartmentResourceGetEnableList,
GetServiceDateTime,
GetLoglist
} from '@/api/api.js'
import {
ElMessage,
@ -165,12 +193,12 @@
let loading = ref(false)
let searchInfo = ref({
dateRange: [],
list_status:null,
patient_type:null,
resources:[],
services_group:null,
reg_num:null,
user_name:null
list_status: null,
patient_type: null,
resources: [],
services_group: null,
reg_num: null,
user_name: null
})
//
let tableData = ref([])
@ -222,7 +250,7 @@
iframe_show.value = true
selectedUrl.value = fileUrl + '/jq_page/appointment.html?' + encodeURIComponent('regnum=' + tableSelected
.value[0].reg_num + '&entrustid=' + tableSelected.value[0].entrust_id + '&episodeid=' + tableSelected
.value[0].episodeid + '&dotype=' + do_type.value)
.value[0].episodeid + '&dotype=' + do_type.value +'&appointment_type=4') //appointment_type=4
console.log(selectedUrl.value)
nextTick(() => {
// const oIframe = document.getElementById('bdIframe')
@ -262,6 +290,7 @@
loading.value = true
CancelYuYue({
MainListId: tableSelected.value[0].id,
reg_num: tableSelected.value[0].reg_num,
password: value
}).then(res => {
loading.value = false
@ -278,14 +307,68 @@
})
})
.catch(() => {
ElMessage({
type: 'info',
message: 'Input canceled'
})
})
}
//
let EnableDeviceList = ref([])
const GetEnableDeviceListFunc = () => {
loading.value = true
GetEnableDeviceList().then(res => {
loading.value = false
if (res.status) {
EnableDeviceList.value = res.data
} else {
ElMessage.error(res.msg)
}
})
}
//
let enableResourceList = ref([])
const getEnableResource = () => {
loading.value = true
DepartmentResourceGetEnableList().then(res => {
loading.value = false
if (res.status) {
enableResourceList.value = res.data
} else {
ElMessage.error(res.msg)
}
})
}
//
const GetServiceDate = () => {
GetServiceDateTime().then(res => {
if (res.status) {
let datetime = res.data.datetime.substr(0, 10)
searchInfo.value.dateRange = [datetime, datetime]
GetList()
}
})
}
//
let LogShow=ref(false);
let LogList=ref(null);
let LogDataShow=ref(false);
const showLog=(row)=>{
LogShow.value=true
GetLoglist({id:row.id}).then(res => {
if (res.status) {
LogList.value=res.data
}
})
}
let LogDataJson=ref('');
const showLogJson=(data)=>{
LogDataShow.value=true
LogDataJson.value=data
}
onMounted(() => {
GetList()
getEnableResource()
GetEnableDeviceListFunc()
GetServiceDate()
})
</script>

@ -0,0 +1,32 @@
<script>
export default {
onLaunch: function() {
console.warn('当前组件仅支持 uni_modules 目录结构 ,请升级 HBuilderX 到 3.1.0 版本以上!')
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style lang="scss">
/*每个页面公共css */
@import '@/uni_modules/uni-scss/index.scss';
/* #ifndef APP-NVUE */
@import '@/static/customicons.css';
//
page {
background-color: #f5f5f5;
}
/* #endif */
.example-info {
font-size: 14px;
color: #333;
padding: 10px;
}
</style>

@ -0,0 +1,38 @@
import {
useHttp
} from '@/tools/http';
const {
isLoading,
sendRequest
} = useHttp();
//let Url='https://service-platform.sixinyun.com'
let Url='http://yijiyuyue'
let BaseUrl=Url+'/api/'
export const BaseFileUrl=()=>{
return Url;
}
//登录授权
export const Login = (data) => {
return sendRequest({url: BaseUrl+"H5/Login",method: 'POST',data:data});
}
//获取个人医嘱
export const EntrustGetList = (data) => {
return sendRequest({url: BaseUrl+"v1/H5/EntrustGetList",method: 'POST',data:data});
}
//获取可预约计划
export const GetEnablePlan = (data) => {
return sendRequest({url: BaseUrl+"v1/H5/GetEnablePlan",method: 'POST',data:data});
}
//预约
export const H5_YuYue = (data) => {
return sendRequest({url: BaseUrl+"v1/H5/H5_YuYue",method: 'POST',data:data});
}
//取消预约
export const H5_CancelYuYue = (data) => {
return sendRequest({url: BaseUrl+"v1/H5/H5_CancelYuYue",method: 'POST',data:data});
}
export const UpFileUrl= () => {
return BaseUrl+'v1/UpFile'
}

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

@ -0,0 +1,25 @@
// #ifndef VUE3
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
import App from './App.vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif

@ -0,0 +1,60 @@
{
"name" : "h5",
"appid" : "__UNI__D2D027F",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
"app-plus" : {
/* 5+App */
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"nvueStyleCompiler" : "uni-app",
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"modules" : {},
/* */
"distribute" : {
/* */
"android" : {
/* android */
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
"ios" : {},
/* ios */
"sdkConfigs" : {}
}
},
/* SDK */
"quickapp" : {},
/* */
"mp-weixin" : {
/* */
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"vueVersion" : "3"
}

@ -0,0 +1,43 @@
{
"pages": [{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app"
}
},
{
"path" : "pages/CheckItemMainList",
"style" :
{
"navigationBarTitleText" : "",
"enablePullDownRefresh" : false,
"navigationStyle": "custom"
}
},
{
"path" : "pages/Login",
"style" :
{
"navigationBarTitleText" : "",
"enablePullDownRefresh" : false
}
},
{
"path" : "pages/PlanList",
"style" :
{
"navigationBarTitleText" : "",
"enablePullDownRefresh" : false,
"navigationStyle": "custom"
}
}],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"app-plus": {
"background": "#efeff4"
}
}
}

@ -0,0 +1,264 @@
<template>
<view class="CheckItemMain">
<view class="head"></view>
<view class="userInfo">
<view class="title">患者信息</view>
<view class="row">
<view class="label" >姓名</view>
<view class="value" >张三</view>
</view>
<view class="row">
<view class="label">性别</view>
<view class="value"></view>
</view>
<view class="row">
<view class="label">手机号</view>
<view class="value">99999</view>
</view>
<view class="row">
<view class="label">注册号</view>
<view class="value">99999</view>
</view>
<view class="date">
<view class="datetime">
<uni-datetime-picker v-model="SearchInfo.dateRange" type="daterange" @change="dateSelecteFunc" />
</view>
</view>
</view>
<view v-if="List.length>0" class="list">
<view class="info" v-for="(item,index) in List">
<view class="item_title">检查项目{{item.entrust}}</view>
<view class="item_info">
<view>医嘱时间<span class="item_value">{{item.entrust_date}}</span></view>
<view>申请科室<span class="item_value">{{item.reservation_department}}</span></view>
<view>状态
<span v-if="item.list_status==0" class="item_value"></span>
<span v-if="item.list_status==1" class="item_value"></span>
<span v-if="item.list_status==2" class="item_value"></span>
<span v-if="item.list_status==3" class="item_value"></span>
</view>
<view v-if="item.list_status==1"><span class="item_value">{{item.reservation_date}} {{item.period_begin_time.substring(0,5)}}~{{item.period_end_time.substring(0,5)}}</span></view>
<view class="button_row" v-if="item.list_status==0">
<view class="button" @click="ToPlanList(1,item)"> </view>
</view>
<view class="button_row" v-if="item.list_status==1">
<view class="button red" @click="Cancel(item)"> </view>
<view class="button blue" @click="ToPlanList(2,item)"> </view>
</view>
</view>
</view>
</view>
<view class="nodata" v-else>
暂无记录
</view>
</view>
</template>
<script setup>
import{ref,onMounted} from "vue"
import {EntrustGetList,H5_CancelYuYue} from "@/api"
import {onLoad,onShow} from "@dcloudio/uni-app"
let SearchInfo=ref({
dateRange:['2021-05-01','2049-01-01'],
})
let List=ref([])
const GetList=()=> {
EntrustGetList({searchInfo:SearchInfo.value}).then(res => {
console.log(res)
if(res.status){
List.value=res.data.list
}
})
}
const dateSelecteFunc=(e)=>{
SearchInfo.value.dateRange=e
GetList()
}
//
const ToPlanList=(do_type,item)=>{
let data={
do_type:do_type,
appointment_type:2,
regnum:item.reg_num,
entrustid:item.entrust_id,
episodeid:item.episodeid
}
uni.navigateTo({
url: '/pages/PlanList?data=' + encodeURIComponent(JSON.stringify(data))
})
}
//
const Cancel=(item)=>{
uni.showModal({
cancelText:"取消",
confirmText:"确定",
title: '提示',
content: '确定取消预约吗?',
success: function (res) {
if (res.confirm) {
H5_CancelYuYue({MainListId:item.id}).then(res => {
console.log(res)
if(res.status){
GetList()
}
})
}
}
});
}
// 1
function getDatesAroundCurrentMonth() {
var today = new Date();
//
function getPreviousMonth(date) {
return new Date(date.getFullYear(), date.getMonth() - 1, date.getDate());
}
//
function getNextMonth(date) {
return new Date(date.getFullYear(), date.getMonth() + 1, date.getDate());
}
// YYYY-MM-DD
function formatDate(date) {
var year = date.getFullYear();
var month = ("0" + (date.getMonth() + 1)).slice(-2); // 0+1
var day = ("0" + date.getDate()).slice(-2);
return year + "-" + month + "-" + day;
}
var currentDateFormatted = formatDate(today);
var previousMonthDate = formatDate(getPreviousMonth(today));
var nextMonthDate = formatDate(getNextMonth(today));
return {
currentDate: currentDateFormatted,
previousMonth: previousMonthDate,
nextMonth: nextMonthDate
};
}
onLoad(()=>{
var dates = getDatesAroundCurrentMonth();
SearchInfo.value.dateRange=[dates.previousMonth,dates.nextMonth]
GetList()
})
</script>
<style scoped>
.CheckItemMain{
height: calc(100vh - 120rpx) ;
background: radial-gradient(circle at top center, #dcdcdc 30%, #e3e3e3, transparent 2%);
padding-top: 30rpx;
}
.userInfo{
background-color: #33cdc9;
margin-left: 20rpx;
margin-right: 20rpx;
border-radius: 30rpx;
padding: 40rpx 40rpx 0rpx 40rpx;
border: 1rpx solid #fff;
}
.userInfo .row{
margin-top: 20rpx;
font-size: 32rpx;
color: #fff;
}
.userInfo .value{
margin-left: 20rpx;
}
.userInfo .label {
text-align: right;
width: 30% ;
}
.row{
display: flex;
}
.junfen{
}
.title{
font-weight: 700;
color:#fff;
}
.date{
text-align: center;
font-size: 30rpx;
background-color: #fff;
padding: 20rpx 60rpx;
border-radius: 30rpx;
box-shadow: 0rpx 10rpx 10rpx #add2d1;
color: #333;
/* transform: translateY(40rpx); */
position: relative;
top: 50rpx;
white-space: nowrap;
}
.datetime{
}
.list{
padding: 20rpx;
}
.info{
margin-top: 60rpx;
padding: 20rpx;
background-color: #fff;
border-radius: 20rpx;
margin-bottom: -20rpx;
}
.item_title{
color:#999;
border-bottom: 1rpx solid #ccc;
padding: 20rpx;
}
.item_info{
padding: 30rpx 50rpx;
color: #333;
}
.item_info view{
margin-top: 20rpx;
}
.item_value{
font-weight: 700;
}
.button{
width: 100%;
height: 60rpx;
line-height: 60rpx;
border-radius: 20rpx;
background-color: #33cdc9;
text-align: center;
color: #fff;
margin-top: 20rpx;
margin-left: 10px;
margin-right: 10px;
}
.red{
background-color: coral;
}
.blue{
background-color: #39a6cd;
}
.button_row{
display: flex;
justify-content: space-between;
}
.nodata{
text-align: center;
margin-top: 100rpx;
color: #ccc;
}
</style>

@ -0,0 +1,31 @@
<template>
<view>
</view>
</template>
<script setup>
import{ref,onMounted} from "vue"
import {Login} from "@/api"
import {onLoad} from "@dcloudio/uni-app"
const LoginFunc=()=> {
Login().then(res => {
console.log(res)
if(res.status){
sessionStorage.setItem("access_token",res.data.token)
sessionStorage.setItem("refresh_token",res.data.refresh_token)
uni.reLaunch({
url: '/pages/CheckItemMainList'
})
}
})
}
onMounted(()=>{
LoginFunc()
})
</script>
<style>
</style>

@ -0,0 +1,211 @@
<template>
<view class="PlanListMain">
<view class="head"></view>
<view class="userInfo" v-if="MianInfo">
<view class="title">选择预约日期及时段</view>
<view class="row">
<view class="label">登记号</view>
<view class="value">{{MianInfo.reg_num}}</view>
</view>
<view class="row">
<view class="label">医嘱</view>
<view class="value">{{MianInfo.entrust}}</view>
</view>
<view class="date">
<view class="datetime">
<uni-datetime-picker v-model="SearchInfo.date" :clear-icon="false" type="date" @change="dateSelecteFunc" />
</view>
</view>
</view>
<view class="list">
<view class="info" v-for="(item,index) in List">
<view>
<view class="row">
<view class="label">执行科室</view>
<view class="value">{{MianInfo.implement_department}}</view>
</view>
<view class="row">
<view class="label">资源</view>
<view class="value">{{item.department_resources_name}}</view>
</view>
<view class="row">
<view class="label">时间段</view>
<view class="value" v-if="item.begin_time">{{item.begin_time.substring(0,5)}}~{{item.end_time.substring(0,5)}}</view>
</view>
</view>
<view class="right">
<view class="right_top">
<view class="button" @click="StartYuYue(item)"></view>
</view>
<view class="right_bottom">已约/总数<span style="color: darkturquoise;">{{item.used_count}}</span>/{{item.count}}</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import{ref,onMounted} from "vue"
import {GetEnablePlan,H5_YuYue} from "@/api"
import {onLoad,onShow} from "@dcloudio/uni-app"
let SearchInfo=ref({
date:'',
})
let List=ref([]);
let MianInfo=ref(null); //
const GetList=()=> {
GetEnablePlan({...SearchInfo.value}).then(res => {
if(res.status){
List.value=res.data.plan_list
MianInfo.value=res.data.mainInfo
SearchInfo.value.mainlistid=MianInfo.value.id
}
})
}
const dateSelecteFunc=(e)=>{
SearchInfo.value.date=e
GetList()
}
const StartYuYue=(item)=>{
uni.showModal({
cancelText:"取消",
confirmText:"确定",
title: '提示',
content: '确定预约 '+SearchInfo.value.date+' '+item.begin_time.substring(0,5)+'~'+item.end_time.substring(0,5)+' 时段吗?',
success: function (res) {
if (res.confirm) {
SearchInfo.value.planid=item.id
H5_YuYue({...SearchInfo.value}).then(res => {
if(res.status){
uni.showToast({
title: '预约成功',
});
setTimeout(function(){
uni.redirectTo({
url: '/pages/CheckItemMainList'
})
},1000)
}
})
}
}
});
}
onLoad((option)=>{
SearchInfo.value = JSON.parse(decodeURIComponent(option.data))
var today = new Date();
// YYYY-MM-DD
function formatDate(date) {
var year = date.getFullYear();
var month = ("0" + (date.getMonth() + 1)).slice(-2); // 0+1
var day = ("0" + date.getDate()).slice(-2);
return year + "-" + month + "-" + day;
}
SearchInfo.value.date = formatDate(today);
GetList()
})
</script>
<style scoped>
.PlanListMain {
height: calc(100vh - 120rpx);
background: radial-gradient(circle at top center, #dcdcdc 30%, #e3e3e3, transparent 2%);
padding-top: 30rpx;
}
.userInfo {
background-color: #33cdc9;
margin-left: 20rpx;
margin-right: 20rpx;
border-radius: 30rpx;
padding: 40rpx 40rpx 0rpx 40rpx;
border: 1rpx solid #fff;
}
.userInfo .row {
margin-top: 20rpx;
font-size: 32rpx;
color: #fff;
}
.userInfo .value {
margin-left: 20rpx;
}
.userInfo .label {
text-align: right;
width: 30%;
}
.row {
display: flex;
}
.date{
text-align: center;
font-size: 30rpx;
background-color: #fff;
padding: 20rpx 60rpx;
border-radius: 30rpx;
box-shadow: 0rpx 10rpx 10rpx #add2d1;
color: #333;
/* transform: translateY(40rpx); */
position: relative;
top: 50rpx;
white-space: nowrap;
}
.title{
font-weight: 700;
color:#fff;
font-size: 32rpx;
}
.list{
margin-top: 60rpx;
padding: 20rpx;
}
.info{
background-color: #fff;
padding: 40rpx 40rpx 20rpx 40rpx;
display: flex;
justify-content: space-between;
border-radius: 20rpx;
color: #333;
}
.info .row{
margin-bottom: 20rpx;
}
.info .row .value{
font-weight: 700;
}
.info .right{
}
.info .right .right_top{
display: flex;
justify-content: center;
}
.info .right .right_bottom{
display: flex;
justify-content: flex-end;
margin-top: 20rpx;
}
.button{
width: 70rpx;
height: 60rpx;
text-align: center;
line-height: 60rpx;
background-color: #33cdc9;
padding: 20rpx;
border-radius: 20rpx;
color: #fff;
}
</style>

@ -0,0 +1,29 @@
<template>
<view class="container">
<view class="intro">本项目已包含uni ui组件无需import和注册可直接使用在代码区键入字母u即可通过代码助手列出所有可用组件光标置于组件名称处按F1即可查看组件文档</view>
<text class="intro">详见</text>
<uni-link :href="href" :text="href"></uni-link>
</view>
</template>
<script>
export default {
data() {
return {
href: 'https://uniapp.dcloud.io/component/README?id=uniui'
}
},
methods: {
}
}
</script>
<style>
.container {
padding: 20px;
font-size: 14px;
line-height: 24px;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

@ -0,0 +1,20 @@
@font-face {
font-family: "customicons"; /* Project id 2878519 */
src:url('/static/customicons.ttf') format('truetype');
}
.customicons {
font-family: "customicons" !important;
}
.youxi:before {
content: "\e60e";
}
.wenjian:before {
content: "\e60f";
}
.zhuanfa:before {
content: "\e610";
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

@ -0,0 +1,78 @@
// http.js
import { ref } from 'vue';
// 封装请求拦截器
function requestInterceptor(options) {
// 在请求发送之前做一些处理
// 比如添加请求头、修改请求参数等
options.header = {
'Authorization': 'Bearer ' + sessionStorage.getItem("access_token"), // 假设需要添加 token
'Content-Type': 'application/json' // 设置请求头
};
return options;
}
// 封装响应拦截器
function responseInterceptor(response) {
// 对响应数据进行处理
// 比如根据响应状态码进行不同的操作
if (response.statusCode === 200) {
// 请求成功
if(response.data.status==false){
uni.showToast({
title: response.data.msg ,
icon: 'none'
});
}
return response.data;
} else {
// 请求失败
uni.showToast({
title: '请求失败,请稍后重试',
icon: 'none'
});
return Promise.reject(response.data);
}
}
// 发送请求的方法,内部使用拦截器
export function useHttp() {
const isLoading = ref(false);
function sendRequest(options) {
isLoading.value = true;
uni.showLoading({
title: '加载中'
});
// 请求发送之前,先经过请求拦截器处理
let processedOptions = requestInterceptor(options);
return new Promise((resolve, reject) => {
uni.request({
...processedOptions,
success: (res) => {
// 请求成功后,经过响应拦截器处理
let processedResponse = responseInterceptor(res);
isLoading.value = false;
uni.hideLoading();
resolve(processedResponse);
},
fail: (err) => {
// 请求失败
isLoading.value = false;
uni.hideLoading();
reject(err);
}
});
});
}
return {
isLoading,
sendRequest
};
}

@ -0,0 +1 @@
@import '@/uni_modules/uni-scss/variables.scss';

@ -0,0 +1,33 @@
## 1.2.22023-01-28
- 修复 运行/打包 控制台警告问题
## 1.2.12022-09-05
- 修复 当 text 超过 max-num 时badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473)
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
## 1.1.72021-11-08
- 优化 升级ui
- 修改 size 属性默认值调整为 small
- 修改 type 属性,默认值调整为 errorinfo 替换 default
## 1.1.62021-09-22
- 修复 在字节小程序上样式不生效的 bug
## 1.1.52021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.42021-07-29
- 修复 去掉 nvue 不支持css 的 align-self 属性nvue 下不暂支持 absolute 属性
## 1.1.32021-06-24
- 优化 示例项目
## 1.1.12021-05-12
- 新增 组件示例地址
## 1.1.02021-05-12
- 新增 uni-badge 的 absolute 属性,支持定位
- 新增 uni-badge 的 offset 属性,支持定位偏移
- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
- 优化 uni-badge 属性 custom-style 支持以对象形式自定义样式
## 1.0.72021-05-07
- 修复 uni-badge 在 App 端数字小于10时不是圆形的bug
- 修复 uni-badge 在父元素不是 flex 布局时宽度缩小的bug
- 新增 uni-badge 属性 custom-style 支持自定义样式
## 1.0.62021-02-04
- 调整为uni_modules目录规范

@ -0,0 +1,268 @@
<template>
<view class="uni-badge--x">
<slot />
<text v-if="text" :class="classNames" :style="[positionStyle, customStyle, dotStyle]"
class="uni-badge" @click="onClick()">{{displayValue}}</text>
</view>
</template>
<script>
/**
* Badge 数字角标
* @description 数字角标一般和其它控件列表9宫格等配合使用用于进行数量提示默认为实心灰色背景
* @tutorial https://ext.dcloud.net.cn/plugin?id=21
* @property {String} text 角标内容
* @property {String} size = [normal|small] 角标内容
* @property {String} type = [info|primary|success|warning|error] 颜色类型
* @value info 灰色
* @value primary 蓝色
* @value success 绿色
* @value warning 黄色
* @value error 红色
* @property {String} inverted = [true|false] 是否无需背景颜色
* @property {Number} maxNum 展示封顶的数字值超过 99 显示 99+
* @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上
* @value rightTop 右上
* @value rightBottom 右下
* @value leftTop 左上
* @value leftBottom 左下
* @property {Array[number]} offset 距定位角中心点的偏移量只有存在 absolute 属性时有效例如[-10, -10] 表示向外偏移 10px[10, 10] 表示向 absolute 指定的内偏移 10px
* @property {String} isDot = [true|false] 是否显示为一个小点
* @event {Function} click 点击 Badge 触发事件
* @example <uni-badge text="1"></uni-badge>
*/
export default {
name: 'UniBadge',
emits: ['click'],
props: {
type: {
type: String,
default: 'error'
},
inverted: {
type: Boolean,
default: false
},
isDot: {
type: Boolean,
default: false
},
maxNum: {
type: Number,
default: 99
},
absolute: {
type: String,
default: ''
},
offset: {
type: Array,
default () {
return [0, 0]
}
},
text: {
type: [String, Number],
default: ''
},
size: {
type: String,
default: 'small'
},
customStyle: {
type: Object,
default () {
return {}
}
}
},
data() {
return {};
},
computed: {
width() {
return String(this.text).length * 8 + 12
},
classNames() {
const {
inverted,
type,
size,
absolute
} = this
return [
inverted ? 'uni-badge--' + type + '-inverted' : '',
'uni-badge--' + type,
'uni-badge--' + size,
absolute ? 'uni-badge--absolute' : ''
].join(' ')
},
positionStyle() {
if (!this.absolute) return {}
let w = this.width / 2,
h = 10
if (this.isDot) {
w = 5
h = 5
}
const x = `${- w + this.offset[0]}px`
const y = `${- h + this.offset[1]}px`
const whiteList = {
rightTop: {
right: x,
top: y
},
rightBottom: {
right: x,
bottom: y
},
leftBottom: {
left: x,
bottom: y
},
leftTop: {
left: x,
top: y
}
}
const match = whiteList[this.absolute]
return match ? match : whiteList['rightTop']
},
dotStyle() {
if (!this.isDot) return {}
return {
width: '10px',
minWidth: '0',
height: '10px',
padding: '0',
borderRadius: '10px'
}
},
displayValue() {
const {
isDot,
text,
maxNum
} = this
return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
}
},
methods: {
onClick() {
this.$emit('click');
}
}
};
</script>
<style lang="scss" >
$uni-primary: #2979ff !default;
$uni-success: #4cd964 !default;
$uni-warning: #f0ad4e !default;
$uni-error: #dd524d !default;
$uni-info: #909399 !default;
$bage-size: 12px;
$bage-small: scale(0.8);
.uni-badge--x {
/* #ifdef APP-NVUE */
// align-self: flex-start;
/* #endif */
/* #ifndef APP-NVUE */
display: inline-block;
/* #endif */
position: relative;
}
.uni-badge--absolute {
position: absolute;
}
.uni-badge--small {
transform: $bage-small;
transform-origin: center center;
}
.uni-badge {
/* #ifndef APP-NVUE */
display: flex;
overflow: hidden;
box-sizing: border-box;
font-feature-settings: "tnum";
min-width: 20px;
/* #endif */
justify-content: center;
flex-direction: row;
height: 20px;
padding: 0 4px;
line-height: 18px;
color: #fff;
border-radius: 100px;
background-color: $uni-info;
background-color: transparent;
border: 1px solid #fff;
text-align: center;
font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-size: $bage-size;
/* #ifdef H5 */
z-index: 999;
cursor: pointer;
/* #endif */
&--info {
color: #fff;
background-color: $uni-info;
}
&--primary {
background-color: $uni-primary;
}
&--success {
background-color: $uni-success;
}
&--warning {
background-color: $uni-warning;
}
&--error {
background-color: $uni-error;
}
&--inverted {
padding: 0 5px 0 0;
color: $uni-info;
}
&--info-inverted {
color: $uni-info;
background-color: transparent;
}
&--primary-inverted {
color: $uni-primary;
background-color: transparent;
}
&--success-inverted {
color: $uni-success;
background-color: transparent;
}
&--warning-inverted {
color: $uni-warning;
background-color: transparent;
}
&--error-inverted {
color: $uni-error;
background-color: transparent;
}
}
</style>

@ -0,0 +1,85 @@
{
"id": "uni-badge",
"displayName": "uni-badge 数字角标",
"version": "1.2.2",
"description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
"keywords": [
"",
"badge",
"uni-ui",
"uniui",
"数字角标",
"徽章"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,10 @@
## Badge 数字角标
> **组件名uni-badge**
> 代码块: `uBadge`
数字角标一般和其它控件列表、9宫格等配合使用用于进行数量提示默认为实心灰色背景
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

@ -0,0 +1,6 @@
## 0.1.22022-06-08
- 修复 微信小程序 separator 不显示的Bug
## 0.1.12022-06-02
- 新增 支持 uni.scss 修改颜色
## 0.1.02022-04-21
- 初始化

@ -0,0 +1,121 @@
<template>
<view class="uni-breadcrumb-item">
<view :class="{
'uni-breadcrumb-item--slot': true,
'uni-breadcrumb-item--slot-link': to && currentPage !== to
}" @click="navTo">
<slot />
</view>
<i v-if="separatorClass" class="uni-breadcrumb-item--separator" :class="separatorClass" />
<text v-else class="uni-breadcrumb-item--separator">{{ separator }}</text>
</view>
</template>
<script>
/**
* BreadcrumbItem 面包屑导航子组件
* @property {String/Object} to 路由跳转页面路径/对象
* @property {Boolean} replace 在使用 to 进行路由跳转时启用 replace 将不会向 history 添加新记录( h5 支持
*/
export default {
data() {
return {
currentPage: ""
}
},
options: {
virtualHost: true
},
props: {
to: {
type: String,
default: ''
},
replace:{
type: Boolean,
default: false
}
},
inject: {
uniBreadcrumb: {
from: "uniBreadcrumb",
default: null
}
},
created(){
const pages = getCurrentPages()
const page = pages[pages.length-1]
if(page){
this.currentPage = `/${page.route}`
}
},
computed: {
separator() {
return this.uniBreadcrumb.separator
},
separatorClass() {
return this.uniBreadcrumb.separatorClass
}
},
methods: {
navTo() {
const { to } = this
if (!to || this.currentPage === to){
return
}
if(this.replace){
uni.redirectTo({
url:to
})
}else{
uni.navigateTo({
url:to
})
}
}
}
}
</script>
<style lang="scss">
$uni-primary: #2979ff !default;
$uni-base-color: #6a6a6a !default;
$uni-main-color: #3a3a3a !default;
.uni-breadcrumb-item {
display: flex;
align-items: center;
white-space: nowrap;
font-size: 14px;
&--slot {
color: $uni-base-color;
padding: 0 10px;
&-link {
color: $uni-main-color;
font-weight: bold;
/* #ifndef APP-NVUE */
cursor: pointer;
/* #endif */
&:hover {
color: $uni-primary;
}
}
}
&--separator {
font-size: 12px;
color: $uni-base-color;
}
&:first-child &--slot {
padding-left: 0;
}
&:last-child &--separator {
display: none;
}
}
</style>

@ -0,0 +1,41 @@
<template>
<view class="uni-breadcrumb">
<slot />
</view>
</template>
<script>
/**
* Breadcrumb 面包屑导航父组件
* @description 显示当前页面的路径快速返回之前的任意页面
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
* @property {String} separator 分隔符默认为斜杠'/'
* @property {String} separatorClass 图标分隔符 class
*/
export default {
options: {
virtualHost: true
},
props: {
separator: {
type: String,
default: '/'
},
separatorClass: {
type: String,
default: ''
}
},
provide() {
return {
uniBreadcrumb: this
}
}
}
</script>
<style lang="scss">
.uni-breadcrumb {
display: flex;
}
</style>

@ -0,0 +1,88 @@
{
"id": "uni-breadcrumb",
"displayName": "uni-breadcrumb 面包屑",
"version": "0.1.2",
"description": "Breadcrumb 面包屑",
"keywords": [
"uni-breadcrumb",
"breadcrumb",
"uni-ui",
"面包屑导航",
"面包屑"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

@ -0,0 +1,66 @@
## breadcrumb 面包屑导航
> **组件名uni-breadcrumb**
> 代码块: `ubreadcrumb`
显示当前页面的路径,快速返回之前的任意页面。
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
### 基本用法
在 ``template`` 中使用组件
```html
<uni-breadcrumb separator="/">
<uni-breadcrumb-item v-for="(route,index) in routes" :key="index" :to="route.to">{{route.name}}</uni-breadcrumb-item>
</uni-breadcrumb>
```
```js
export default {
name: "uni-stat-breadcrumb",
data() {
return {
routes: [{
to: '/A',
name: 'A页面'
}, {
to: '/B',
name: 'B页面'
}, {
to: '/C',
name: 'C页面'
}]
};
}
}
```
## API
### Breadcrumb Props
|属性名 |类型 |默认值 |说明 |
|:-: |:-: |:-: |:-: |
|separator |String |斜杠'/' |分隔符 |
|separatorClass |String | |图标分隔符 class |
### Breadcrumb Item Props
|属性名 |类型 |默认值 |说明 |
|:-: |:-: |:-: |:-: |
|to |String | |路由跳转页面路径 |
|replace|Boolean | |在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录(仅 h5 支持) |
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/breadcrumb/breadcrumb](https://hellouniapp.dcloud.net.cn/pages/extUI/breadcrumb/breadcrumb)

@ -0,0 +1,26 @@
## 1.4.102023-04-10
- 修复 某些情况 monthSwitch 未触发的Bug
## 1.4.92023-02-02
- 修复 某些情况切换月份错误的Bug
## 1.4.82023-01-30
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/161964)
## 1.4.72022-09-16
- 优化 支持使用 uni-scss 控制主题色
## 1.4.62022-09-08
- 修复 表头年月切换导致改变当前日期为选择月1号且未触发change事件的Bug
## 1.4.52022-02-25
- 修复 条件编译 nvue 不支持的 css 样式的Bug
## 1.4.42022-02-25
- 修复 条件编译 nvue 不支持的 css 样式的Bug
## 1.4.32021-09-22
- 修复 startDate、 endDate 属性失效的Bug
## 1.4.22021-08-24
- 新增 支持国际化
## 1.4.12021-08-05
- 修复 弹出层被 tabbar 遮盖的Bug
## 1.4.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.3.162021-05-12
- 新增 组件示例地址
## 1.3.152021-02-04
- 调整为uni_modules目录规范

@ -0,0 +1,546 @@
/**
* @1900-2100区间内的公历农历互转
* @charset UTF-8
* @github https://github.com/jjonline/calendar.js
* @Author Jea杨(JJonline@JJonline.Cn)
* @Time 2014-7-21
* @Time 2016-8-13 Fixed 2033hexAttribution Annals
* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
* @Version 1.0.3
* @公历转农历calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
* @农历转公历calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
*/
/* eslint-disable */
var calendar = {
/**
* 农历1900-2100的润大小信息表
* @Array Of Property
* @return Hex
*/
lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
/** Add By JJonline@JJonline.Cn**/
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
0x0d520], // 2100
/**
* 公历每个月份的天数普通表
* @Array Of Property
* @return Number
*/
solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
/**
* 天干地支之天干速查表
* @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
* @return Cn string
*/
Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
/**
* 天干地支之地支速查表
* @Array Of Property
* @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
* @return Cn string
*/
Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
/**
* 天干地支之地支速查表<=>生肖
* @Array Of Property
* @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
* @return Cn string
*/
Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
/**
* 24节气速查表
* @Array Of Property
* @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
* @return Cn string
*/
solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
/**
* 1900-2100各年的24节气日期速查表
* @Array Of Property
* @return 0x string For splice
*/
sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
'97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
'97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
'97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
'97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
'97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
'9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
'97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
'97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
'7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
'97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
'977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
'7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
'7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
'665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
/**
* 数字转中文速查表
* @Array Of Property
* @trans ['日','一','二','三','四','五','六','七','八','九','十']
* @return Cn string
*/
nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
/**
* 日期转农历称呼速查表
* @Array Of Property
* @trans ['初','十','廿','卅']
* @return Cn string
*/
nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
/**
* 月份转农历称呼速查表
* @Array Of Property
* @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
* @return Cn string
*/
nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
/**
* 返回农历y年一整年的总天数
* @param lunar Year
* @return Number
* @eg:var count = calendar.lYearDays(1987) ;//count=387
*/
lYearDays: function (y) {
var i; var sum = 348
for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
return (sum + this.leapDays(y))
},
/**
* 返回农历y年闰月是哪个月若y年没有闰月 则返回0
* @param lunar Year
* @return Number (0-12)
* @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
*/
leapMonth: function (y) { // 闰字编码 \u95f0
return (this.lunarInfo[y - 1900] & 0xf)
},
/**
* 返回农历y年闰月的天数 若该年没有闰月则返回0
* @param lunar Year
* @return Number (02930)
* @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
*/
leapDays: function (y) {
if (this.leapMonth(y)) {
return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
}
return (0)
},
/**
* 返回农历y年m月非闰月的总天数计算m为闰月时的天数请使用leapDays方法
* @param lunar Year
* @return Number (-12930)
* @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
*/
monthDays: function (y, m) {
if (m > 12 || m < 1) { return -1 }// 月份参数从1至12参数错误返回-1
return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
},
/**
* 返回公历(!)y年m月的天数
* @param solar Year
* @return Number (-128293031)
* @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
*/
solarDays: function (y, m) {
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
var ms = m - 1
if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
} else {
return (this.solarMonth[ms])
}
},
/**
* 农历年份转换为干支纪年
* @param lYear 农历年的年份数
* @return Cn string
*/
toGanZhiYear: function (lYear) {
var ganKey = (lYear - 3) % 10
var zhiKey = (lYear - 3) % 12
if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
},
/**
* 公历月日判断所属星座
* @param cMonth [description]
* @param cDay [description]
* @return Cn string
*/
toAstro: function (cMonth, cDay) {
var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
},
/**
* 传入offset偏移量返回干支
* @param offset 相对甲子的偏移量
* @return Cn string
*/
toGanZhi: function (offset) {
return this.Gan[offset % 10] + this.Zhi[offset % 12]
},
/**
* 传入公历(!)y年获得该年第n个节气的公历日期
* @param y公历年(1900-2100)n二十四节气中的第几个节气(1~24)从n=1(小寒)算起
* @return day Number
* @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
*/
getTerm: function (y, n) {
if (y < 1900 || y > 2100) { return -1 }
if (n < 1 || n > 24) { return -1 }
var _table = this.sTermInfo[y - 1900]
var _info = [
parseInt('0x' + _table.substr(0, 5)).toString(),
parseInt('0x' + _table.substr(5, 5)).toString(),
parseInt('0x' + _table.substr(10, 5)).toString(),
parseInt('0x' + _table.substr(15, 5)).toString(),
parseInt('0x' + _table.substr(20, 5)).toString(),
parseInt('0x' + _table.substr(25, 5)).toString()
]
var _calday = [
_info[0].substr(0, 1),
_info[0].substr(1, 2),
_info[0].substr(3, 1),
_info[0].substr(4, 2),
_info[1].substr(0, 1),
_info[1].substr(1, 2),
_info[1].substr(3, 1),
_info[1].substr(4, 2),
_info[2].substr(0, 1),
_info[2].substr(1, 2),
_info[2].substr(3, 1),
_info[2].substr(4, 2),
_info[3].substr(0, 1),
_info[3].substr(1, 2),
_info[3].substr(3, 1),
_info[3].substr(4, 2),
_info[4].substr(0, 1),
_info[4].substr(1, 2),
_info[4].substr(3, 1),
_info[4].substr(4, 2),
_info[5].substr(0, 1),
_info[5].substr(1, 2),
_info[5].substr(3, 1),
_info[5].substr(4, 2)
]
return parseInt(_calday[n - 1])
},
/**
* 传入农历数字月份返回汉语通俗表示法
* @param lunar month
* @return Cn string
* @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
*/
toChinaMonth: function (m) { // 月 => \u6708
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
var s = this.nStr3[m - 1]
s += '\u6708'// 加上月字
return s
},
/**
* 传入农历日期数字返回汉字表示法
* @param lunar day
* @return Cn string
* @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
*/
toChinaDay: function (d) { // 日 => \u65e5
var s
switch (d) {
case 10:
s = '\u521d\u5341'; break
case 20:
s = '\u4e8c\u5341'; break
break
case 30:
s = '\u4e09\u5341'; break
break
default :
s = this.nStr2[Math.floor(d / 10)]
s += this.nStr1[d % 10]
}
return (s)
},
/**
* 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是立春
* @param y year
* @return Cn string
* @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
*/
getAnimal: function (y) {
return this.Animals[(y - 4) % 12]
},
/**
* 传入阳历年月日获得详细的公历农历object信息 <=>JSON
* @param y solar year
* @param m solar month
* @param d solar day
* @return JSON object
* @eg:console.log(calendar.solar2lunar(1987,11,01));
*/
solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
// 年份限定、上限
if (y < 1900 || y > 2100) {
return -1// undefined转换为数字变为NaN
}
// 公历传参最下限
if (y == 1900 && m == 1 && d < 31) {
return -1
}
// 未传参 获得当天
if (!y) {
var objDate = new Date()
} else {
var objDate = new Date(y, parseInt(m) - 1, d)
}
var i; var leap = 0; var temp = 0
// 修正ymd参数
var y = objDate.getFullYear()
var m = objDate.getMonth() + 1
var d = objDate.getDate()
var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
for (i = 1900; i < 2101 && offset > 0; i++) {
temp = this.lYearDays(i)
offset -= temp
}
if (offset < 0) {
offset += temp; i--
}
// 是否今天
var isTodayObj = new Date()
var isToday = false
if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
isToday = true
}
// 星期几
var nWeek = objDate.getDay()
var cWeek = this.nStr1[nWeek]
// 数字表示周几顺应天朝周一开始的惯例
if (nWeek == 0) {
nWeek = 7
}
// 农历年
var year = i
var leap = this.leapMonth(i) // 闰哪个月
var isLeap = false
// 效验闰月
for (i = 1; i < 13 && offset > 0; i++) {
// 闰月
if (leap > 0 && i == (leap + 1) && isLeap == false) {
--i
isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
} else {
temp = this.monthDays(year, i)// 计算农历普通月天数
}
// 解除闰月
if (isLeap == true && i == (leap + 1)) { isLeap = false }
offset -= temp
}
// 闰月导致数组下标重叠取反
if (offset == 0 && leap > 0 && i == leap + 1) {
if (isLeap) {
isLeap = false
} else {
isLeap = true; --i
}
}
if (offset < 0) {
offset += temp; --i
}
// 农历月
var month = i
// 农历日
var day = offset + 1
// 天干地支处理
var sm = m - 1
var gzY = this.toGanZhiYear(year)
// 当月的两个节气
// bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
// 依据12节气修正干支月
var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
if (d >= firstNode) {
gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
}
// 传入的日期的节气与否
var isTerm = false
var Term = null
if (firstNode == d) {
isTerm = true
Term = this.solarTerm[m * 2 - 2]
}
if (secondNode == d) {
isTerm = true
Term = this.solarTerm[m * 2 - 1]
}
// 日柱 当月一日与 1900/1/1 相差天数
var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
var gzD = this.toGanZhi(dayCyclical + d - 1)
// 该日期所属的星座
var astro = this.toAstro(m, d)
return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
},
/**
* 传入农历年月日以及传入的月份是否闰月获得详细的公历农历object信息 <=>JSON
* @param y lunar year
* @param m lunar month
* @param d lunar day
* @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
* @return JSON object
* @eg:console.log(calendar.lunar2solar(1987,9,10));
*/
lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
var isLeapMonth = !!isLeapMonth
var leapOffset = 0
var leapMonth = this.leapMonth(y)
var leapDay = this.leapDays(y)
if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
var day = this.monthDays(y, m)
var _day = day
// bugFix 2016-9-25
// if month is leap, _day use leapDays method
if (isLeapMonth) {
_day = this.leapDays(y, m)
}
if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
// 计算农历的时间差
var offset = 0
for (var i = 1900; i < y; i++) {
offset += this.lYearDays(i)
}
var leap = 0; var isAdd = false
for (var i = 1; i < m; i++) {
leap = this.leapMonth(y)
if (!isAdd) { // 处理闰月
if (leap <= i && leap > 0) {
offset += this.leapDays(y); isAdd = true
}
}
offset += this.monthDays(y, i)
}
// 转换闰月农历 需补充该年闰月的前一个月的时差
if (isLeapMonth) { offset += day }
// 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
var calObj = new Date((offset + d - 31) * 86400000 + stmap)
var cY = calObj.getUTCFullYear()
var cM = calObj.getUTCMonth() + 1
var cD = calObj.getUTCDate()
return this.solar2lunar(cY, cM, cD)
}
}
export default calendar

@ -0,0 +1,12 @@
{
"uni-calender.ok": "ok",
"uni-calender.cancel": "cancel",
"uni-calender.today": "today",
"uni-calender.MON": "MON",
"uni-calender.TUE": "TUE",
"uni-calender.WED": "WED",
"uni-calender.THU": "THU",
"uni-calender.FRI": "FRI",
"uni-calender.SAT": "SAT",
"uni-calender.SUN": "SUN"
}

@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

@ -0,0 +1,12 @@
{
"uni-calender.ok": "确定",
"uni-calender.cancel": "取消",
"uni-calender.today": "今日",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六"
}

@ -0,0 +1,12 @@
{
"uni-calender.ok": "確定",
"uni-calender.cancel": "取消",
"uni-calender.today": "今日",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六"
}

@ -0,0 +1,187 @@
<template>
<view class="uni-calendar-item__weeks-box" :class="{
'uni-calendar-item--disable':weeks.disable,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) ,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
}"
@click="choiceDate(weeks)">
<view class="uni-calendar-item__weeks-box-item">
<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
<text class="uni-calendar-item__weeks-box-text" :class="{
'uni-calendar-item--isDay-text': weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">{{weeks.date}}</text>
<text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
}">{{todayText}}</text>
<text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">{{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
<text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--extra':weeks.extraInfo.info,
'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">{{weeks.extraInfo.info}}</text>
</view>
</view>
</template>
<script>
import { initVueI18n } from '@dcloudio/uni-i18n'
import i18nMessages from './i18n/index.js'
const { t } = initVueI18n(i18nMessages)
export default {
emits:['change'],
props: {
weeks: {
type: Object,
default () {
return {}
}
},
calendar: {
type: Object,
default: () => {
return {}
}
},
selected: {
type: Array,
default: () => {
return []
}
},
lunar: {
type: Boolean,
default: false
}
},
computed: {
todayText() {
return t("uni-calender.today")
},
},
methods: {
choiceDate(weeks) {
this.$emit('change', weeks)
}
}
}
</script>
<style lang="scss" scoped>
$uni-font-size-base:14px;
$uni-text-color:#333;
$uni-font-size-sm:12px;
$uni-color-error: #e43d33;
$uni-opacity-disabled: 0.3;
$uni-text-color-disable:#c0c0c0;
$uni-primary: #2979ff !default;
.uni-calendar-item__weeks-box {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
}
.uni-calendar-item__weeks-box-text {
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.uni-calendar-item__weeks-lunar-text {
font-size: $uni-font-size-sm;
color: $uni-text-color;
}
.uni-calendar-item__weeks-box-item {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
width: 100rpx;
height: 100rpx;
}
.uni-calendar-item__weeks-box-circle {
position: absolute;
top: 5px;
right: 5px;
width: 8px;
height: 8px;
border-radius: 8px;
background-color: $uni-color-error;
}
.uni-calendar-item--disable {
background-color: rgba(249, 249, 249, $uni-opacity-disabled);
color: $uni-text-color-disable;
}
.uni-calendar-item--isDay-text {
color: $uni-primary;
}
.uni-calendar-item--isDay {
background-color: $uni-primary;
opacity: 0.8;
color: #fff;
}
.uni-calendar-item--extra {
color: $uni-color-error;
opacity: 0.8;
}
.uni-calendar-item--checked {
background-color: $uni-primary;
color: #fff;
opacity: 0.8;
}
.uni-calendar-item--multiple {
background-color: $uni-primary;
color: #fff;
opacity: 0.8;
}
.uni-calendar-item--before-checked {
background-color: #ff5a5f;
color: #fff;
}
.uni-calendar-item--after-checked {
background-color: #ff5a5f;
color: #fff;
}
</style>

@ -0,0 +1,566 @@
<template>
<view class="uni-calendar">
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view>
<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
<view class="uni-calendar__header-btn-box" @click="close">
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text>
</view>
<view class="uni-calendar__header-btn-box" @click="confirm">
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text>
</view>
</view>
<view class="uni-calendar__header">
<view class="uni-calendar__header-btn-box" @click.stop="pre">
<view class="uni-calendar__header-btn uni-calendar--left"></view>
</view>
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
<text class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
</picker>
<view class="uni-calendar__header-btn-box" @click.stop="next">
<view class="uni-calendar__header-btn uni-calendar--right"></view>
</view>
<text class="uni-calendar__backtoday" @click="backToday">{{todayText}}</text>
</view>
<view class="uni-calendar__box">
<view v-if="showMonth" class="uni-calendar__box-bg">
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
</view>
<view class="uni-calendar__weeks">
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{monText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
</view>
</view>
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></calendar-item>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import Calendar from './util.js';
import CalendarItem from './uni-calendar-item.vue'
import { initVueI18n } from '@dcloudio/uni-i18n'
import i18nMessages from './i18n/index.js'
const { t } = initVueI18n(i18nMessages)
/**
* Calendar 日历
* @description 日历组件可以查看日期选择任意范围内的日期打点操作常用场景如酒店日期预订火车机票选择购买日期上下班打卡等
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
* @property {String} date 自定义当前时间默认为今天
* @property {Boolean} lunar 显示农历
* @property {String} startDate 日期选择范围-开始日期
* @property {String} endDate 日期选择范围-结束日期
* @property {Boolean} range 范围选择
* @property {Boolean} insert = [true|false] 插入模式,默认为false
* @value true 弹窗模式
* @value false 插入模式
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
* @property {Array} selected 打点期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
* @property {Boolean} showMonth 是否选择月份为背景
* @event {Function} change 日期改变`insert :ture` 时生效
* @event {Function} confirm 确认选择`insert :false` 时生效
* @event {Function} monthSwitch 切换月份时触发
* @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
*/
export default {
components: {
CalendarItem
},
emits:['close','confirm','change','monthSwitch'],
props: {
date: {
type: String,
default: ''
},
selected: {
type: Array,
default () {
return []
}
},
lunar: {
type: Boolean,
default: false
},
startDate: {
type: String,
default: ''
},
endDate: {
type: String,
default: ''
},
range: {
type: Boolean,
default: false
},
insert: {
type: Boolean,
default: true
},
showMonth: {
type: Boolean,
default: true
},
clearDate: {
type: Boolean,
default: true
}
},
data() {
return {
show: false,
weeks: [],
calendar: {},
nowDate: '',
aniMaskShow: false
}
},
computed:{
/**
* for i18n
*/
okText() {
return t("uni-calender.ok")
},
cancelText() {
return t("uni-calender.cancel")
},
todayText() {
return t("uni-calender.today")
},
monText() {
return t("uni-calender.MON")
},
TUEText() {
return t("uni-calender.TUE")
},
WEDText() {
return t("uni-calender.WED")
},
THUText() {
return t("uni-calender.THU")
},
FRIText() {
return t("uni-calender.FRI")
},
SATText() {
return t("uni-calender.SAT")
},
SUNText() {
return t("uni-calender.SUN")
},
},
watch: {
date(newVal) {
// this.cale.setDate(newVal)
this.init(newVal)
},
startDate(val){
this.cale.resetSatrtDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
endDate(val){
this.cale.resetEndDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
selected(newVal) {
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
this.weeks = this.cale.weeks
}
},
created() {
this.cale = new Calendar({
selected: this.selected,
startDate: this.startDate,
endDate: this.endDate,
range: this.range,
})
this.init(this.date)
},
methods: {
// 穿
clean() {},
bindDateChange(e) {
const value = e.detail.value + '-1'
this.setDate(value)
const { year,month } = this.cale.getDate(value)
this.$emit('monthSwitch', {
year,
month
})
},
/**
* 初始化日期显示
* @param {Object} date
*/
init(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks
this.nowDate = this.calendar = this.cale.getInfo(date)
},
/**
* 打开日历弹窗
*/
open() {
//
if (this.clearDate && !this.insert) {
this.cale.cleanMultipleStatus()
// this.cale.setDate(this.date)
this.init(this.date)
}
this.show = true
this.$nextTick(() => {
setTimeout(() => {
this.aniMaskShow = true
}, 50)
})
},
/**
* 关闭日历弹窗
*/
close() {
this.aniMaskShow = false
this.$nextTick(() => {
setTimeout(() => {
this.show = false
this.$emit('close')
}, 300)
})
},
/**
* 确认按钮
*/
confirm() {
this.setEmit('confirm')
this.close()
},
/**
* 变化触发
*/
change() {
if (!this.insert) return
this.setEmit('change')
},
/**
* 选择月份触发
*/
monthSwitch() {
let {
year,
month
} = this.nowDate
this.$emit('monthSwitch', {
year,
month: Number(month)
})
},
/**
* 派发事件
* @param {Object} name
*/
setEmit(name) {
let {
year,
month,
date,
fullDate,
lunar,
extraInfo
} = this.calendar
this.$emit(name, {
range: this.cale.multipleStatus,
year,
month,
date,
fulldate: fullDate,
lunar,
extraInfo: extraInfo || {}
})
},
/**
* 选择天触发
* @param {Object} weeks
*/
choiceDate(weeks) {
if (weeks.disable) return
this.calendar = weeks
//
this.cale.setMultiple(this.calendar.fullDate)
this.weeks = this.cale.weeks
this.change()
},
/**
* 回到今天
*/
backToday() {
const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
const date = this.cale.getDate(new Date())
const todayYearMonth = `${date.year}-${date.month}`
if(nowYearMonth !== todayYearMonth) {
this.monthSwitch()
}
this.init(date.fullDate)
this.change()
},
/**
* 上个月
*/
pre() {
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
this.setDate(preDate)
this.monthSwitch()
},
/**
* 下个月
*/
next() {
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
this.setDate(nextDate)
this.monthSwitch()
},
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks
this.nowDate = this.cale.getInfo(date)
}
}
}
</script>
<style lang="scss" scoped>
$uni-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
$uni-border-color: #EDEDED;
$uni-text-color: #333;
$uni-bg-color-hover:#f1f1f1;
$uni-font-size-base:14px;
$uni-text-color-placeholder: #808080;
$uni-color-subtitle: #555555;
$uni-text-color-grey:#999;
.uni-calendar {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.uni-calendar__mask {
position: fixed;
bottom: 0;
top: 0;
left: 0;
right: 0;
background-color: $uni-bg-color-mask;
transition-property: opacity;
transition-duration: 0.3s;
opacity: 0;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--mask-show {
opacity: 1
}
.uni-calendar--fixed {
position: fixed;
/* #ifdef APP-NVUE */
bottom: 0;
/* #endif */
left: 0;
right: 0;
transition-property: transform;
transition-duration: 0.3s;
transform: translateY(460px);
/* #ifndef APP-NVUE */
bottom: calc(var(--window-bottom));
z-index: 99;
/* #endif */
}
.uni-calendar--ani-show {
transform: translateY(0);
}
.uni-calendar__content {
background-color: #fff;
}
.uni-calendar__header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
height: 50px;
border-bottom-color: $uni-border-color;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar--fixed-top {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 1px;
}
.uni-calendar--fixed-width {
width: 50px;
}
.uni-calendar__backtoday {
position: absolute;
right: 0;
top: 25rpx;
padding: 0 5px;
padding-left: 10px;
height: 25px;
line-height: 25px;
font-size: 12px;
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
color: $uni-text-color;
background-color: $uni-bg-color-hover;
}
.uni-calendar__header-text {
text-align: center;
width: 100px;
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.uni-calendar__header-btn-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
}
.uni-calendar__header-btn {
width: 10px;
height: 10px;
border-left-color: $uni-text-color-placeholder;
border-left-style: solid;
border-left-width: 2px;
border-top-color: $uni-color-subtitle;
border-top-style: solid;
border-top-width: 2px;
}
.uni-calendar--left {
transform: rotate(-45deg);
}
.uni-calendar--right {
transform: rotate(135deg);
}
.uni-calendar__weeks {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-calendar__weeks-item {
flex: 1;
}
.uni-calendar__weeks-day {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
height: 45px;
border-bottom-color: #F5F5F5;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar__weeks-day-text {
font-size: 14px;
}
.uni-calendar__box {
position: relative;
}
.uni-calendar__box-bg {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.uni-calendar__box-bg-text {
font-size: 200px;
font-weight: bold;
color: $uni-text-color-grey;
opacity: 0.1;
text-align: center;
/* #ifndef APP-NVUE */
line-height: 1;
/* #endif */
}
</style>

@ -0,0 +1,360 @@
import CALENDAR from './calendar.js'
class Calendar {
constructor({
date,
selected,
startDate,
endDate,
range
} = {}) {
// 当前日期
this.date = this.getDate(new Date()) // 当前初入日期
// 打点信息
this.selected = selected || [];
// 范围开始
this.startDate = startDate
// 范围结束
this.endDate = endDate
this.range = range
// 多选状态
this.cleanMultipleStatus()
// 每周日期
this.weeks = {}
// this._getWeek(this.date.fullDate)
}
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this.selectDate = this.getDate(date)
this._getWeek(this.selectDate.fullDate)
}
/**
* 清理多选状态
*/
cleanMultipleStatus() {
this.multipleStatus = {
before: '',
after: '',
data: []
}
}
/**
* 重置开始日期
*/
resetSatrtDate(startDate) {
// 范围开始
this.startDate = startDate
}
/**
* 重置结束日期
*/
resetEndDate(endDate) {
// 范围结束
this.endDate = endDate
}
/**
* 获取任意时间
*/
getDate(date, AddDayCount = 0, str = 'day') {
if (!date) {
date = new Date()
}
if (typeof date !== 'object') {
date = date.replace(/-/g, '/')
}
const dd = new Date(date)
switch (str) {
case 'day':
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
break
case 'month':
if (dd.getDate() === 31 && AddDayCount>0) {
dd.setDate(dd.getDate() + AddDayCount)
} else {
const preMonth = dd.getMonth()
dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
const nextMonth = dd.getMonth()
// 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
if(AddDayCount<0 && preMonth!==0 && nextMonth-preMonth>AddDayCount){
dd.setMonth(nextMonth+(nextMonth-preMonth+AddDayCount))
}
// 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
if(AddDayCount>0 && nextMonth-preMonth>AddDayCount){
dd.setMonth(nextMonth-(nextMonth-preMonth-AddDayCount))
}
}
break
case 'year':
dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
break
}
const y = dd.getFullYear()
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期不足10补0
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号不足10补0
return {
fullDate: y + '-' + m + '-' + d,
year: y,
month: m,
date: d,
day: dd.getDay()
}
}
/**
* 获取上月剩余天数
*/
_getLastMonthDays(firstDay, full) {
let dateArr = []
for (let i = firstDay; i > 0; i--) {
const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
dateArr.push({
date: beforeDate,
month: full.month - 1,
lunar: this.getlunar(full.year, full.month - 1, beforeDate),
disable: true
})
}
return dateArr
}
/**
* 获取本月天数
*/
_currentMonthDys(dateData, full) {
let dateArr = []
let fullDate = this.date.fullDate
for (let i = 1; i <= dateData; i++) {
let nowDate = full.year + '-' + (full.month < 10 ?
full.month : full.month) + '-' + (i < 10 ?
'0' + i : i)
// 是否今天
let isDay = fullDate === nowDate
// 获取打点信息
let info = this.selected && this.selected.find((item) => {
if (this.dateEqual(nowDate, item.date)) {
return item
}
})
// 日期禁用
let disableBefore = true
let disableAfter = true
if (this.startDate) {
// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
disableBefore = this.dateCompare(this.startDate, nowDate)
}
if (this.endDate) {
// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
disableAfter = this.dateCompare(nowDate, this.endDate)
}
let multiples = this.multipleStatus.data
let checked = false
let multiplesStatus = -1
if (this.range) {
if (multiples) {
multiplesStatus = multiples.findIndex((item) => {
return this.dateEqual(item, nowDate)
})
}
if (multiplesStatus !== -1) {
checked = true
}
}
let data = {
fullDate: nowDate,
year: full.year,
date: i,
multiple: this.range ? checked : false,
beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
month: full.month,
lunar: this.getlunar(full.year, full.month, i),
disable: !(disableBefore && disableAfter),
isDay
}
if (info) {
data.extraInfo = info
}
dateArr.push(data)
}
return dateArr
}
/**
* 获取下月天数
*/
_getNextMonthDays(surplus, full) {
let dateArr = []
for (let i = 1; i < surplus + 1; i++) {
dateArr.push({
date: i,
month: Number(full.month) + 1,
lunar: this.getlunar(full.year, Number(full.month) + 1, i),
disable: true
})
}
return dateArr
}
/**
* 获取当前日期详情
* @param {Object} date
*/
getInfo(date) {
if (!date) {
date = new Date()
}
const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
return dateInfo
}
/**
* 比较时间大小
*/
dateCompare(startDate, endDate) {
// 计算截止时间
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
// 计算详细项的截止时间
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
if (startDate <= endDate) {
return true
} else {
return false
}
}
/**
* 比较时间是否相等
*/
dateEqual(before, after) {
// 计算截止时间
before = new Date(before.replace('-', '/').replace('-', '/'))
// 计算详细项的截止时间
after = new Date(after.replace('-', '/').replace('-', '/'))
if (before.getTime() - after.getTime() === 0) {
return true
} else {
return false
}
}
/**
* 获取日期范围内所有日期
* @param {Object} begin
* @param {Object} end
*/
geDateAll(begin, end) {
var arr = []
var ab = begin.split('-')
var ae = end.split('-')
var db = new Date()
db.setFullYear(ab[0], ab[1] - 1, ab[2])
var de = new Date()
de.setFullYear(ae[0], ae[1] - 1, ae[2])
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
for (var k = unixDb; k <= unixDe;) {
k = k + 24 * 60 * 60 * 1000
arr.push(this.getDate(new Date(parseInt(k))).fullDate)
}
return arr
}
/**
* 计算阴历日期显示
*/
getlunar(year, month, date) {
return CALENDAR.solar2lunar(year, month, date)
}
/**
* 设置打点
*/
setSelectInfo(data, value) {
this.selected = value
this._getWeek(data)
}
/**
* 获取多选状态
*/
setMultiple(fullDate) {
let {
before,
after
} = this.multipleStatus
if (!this.range) return
if (before && after) {
this.multipleStatus.before = ''
this.multipleStatus.after = ''
this.multipleStatus.data = []
} else {
if (!before) {
this.multipleStatus.before = fullDate
} else {
this.multipleStatus.after = fullDate
if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
} else {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
}
}
}
this._getWeek(fullDate)
}
/**
* 获取每周数据
* @param {Object} dateData
*/
_getWeek(dateData) {
const {
year,
month
} = this.getDate(dateData)
let firstDay = new Date(year, month - 1, 1).getDay()
let currentDay = new Date(year, month, 0).getDate()
let dates = {
lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
nextMonthDays: [], // 下个月开始几天
weeks: []
}
let canlender = []
const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
let weeks = {}
// 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
for (let i = 0; i < canlender.length; i++) {
if (i % 7 === 0) {
weeks[parseInt(i / 7)] = new Array(7)
}
weeks[parseInt(i / 7)][i % 7] = canlender[i]
}
this.canlender = canlender
this.weeks = weeks
}
//静态方法
// static init(date) {
// if (!this.instance) {
// this.instance = new Calendar(date);
// }
// return this.instance;
// }
}
export default Calendar

@ -0,0 +1,85 @@
{
"id": "uni-calendar",
"displayName": "uni-calendar 日历",
"version": "1.4.10",
"description": "日历组件",
"keywords": [
"uni-ui",
"uniui",
"日历",
"",
"打卡",
"日历选择"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,103 @@
## Calendar 日历
> **组件名uni-calendar**
> 代码块: `uCalendar`
日历组件
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 本组件农历转换使用的js是 [@1900-2100区间内的公历、农历互转](https://github.com/jjonline/calendar.js)
> - 仅支持自定义组件模式
> - `date`属性传入的应该是一个 String ,如: 2019-06-27 ,而不是 new Date()
> - 通过 `insert` 属性来确定当前的事件是 @change 还是 @confirm 。理应合并为一个事件,但是为了区分模式,现使用两个事件,这里需要注意
> - 弹窗模式下无法阻止后面的元素滚动,如有需要阻止,请在弹窗弹出后,手动设置滚动元素为不可滚动
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
### 基本用法
在 ``template`` 中使用组件
```html
<view>
<uni-calendar
:insert="true"
:lunar="true"
:start-date="'2019-3-2'"
:end-date="'2019-5-20'"
@change="change"
/>
</view>
```
### 通过方法打开日历
需要设置 `insert``false`
```html
<view>
<uni-calendar
ref="calendar"
:insert="false"
@confirm="confirm"
/>
<button @click="open">打开日历</button>
</view>
```
```javascript
export default {
data() {
return {};
},
methods: {
open(){
this.$refs.calendar.open();
},
confirm(e) {
console.log(e);
}
}
};
```
## API
### Calendar Props
| 属性名 | 类型 | 默认值| 说明 |
| - | - | - | - |
| date | String |- | 自定义当前时间,默认为今天 |
| lunar | Boolean | false | 显示农历 |
| startDate | String |- | 日期选择范围-开始日期 |
| endDate | String |- | 日期选择范围-结束日期 |
| range | Boolean | false | 范围选择 |
| insert | Boolean | false | 插入模式,可选值ture插入模式false弹窗模式默认为插入模式 |
|clearDate |Boolean |true |弹窗模式是否清空上次选择内容 |
| selected | Array |- | 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] |
|showMonth | Boolean | true | 是否显示月份为背景 |
### Calendar Events
| 事件名 | 说明 |返回值|
| - | - | - |
| open | 弹出日历组件,`insert :false` 时生效|- |
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar](https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar)

@ -0,0 +1,26 @@
## 1.3.12021-12-20
- 修复 在vue页面下略缩图显示不正常的bug
## 1.3.02021-11-19
- 重构插槽的用法 header 替换为 title
- 新增 actions 插槽
- 新增 cover 封面图属性和插槽
- 新增 padding 内容默认内边距离
- 新增 margin 卡片默认外边距离
- 新增 spacing 卡片默认内边距
- 新增 shadow 卡片阴影属性
- 取消 mode 属性,可使用组合插槽代替
- 取消 note 属性 使用actions插槽代替
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-card](https://uniapp.dcloud.io/component/uniui/uni-card)
## 1.2.12021-07-30
- 优化 vue3下事件警告的问题
## 1.2.02021-07-13
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.82021-07-01
- 优化 图文卡片无图片加载时,提供占位图标
- 新增 header 插槽,自定义卡片头部( 图文卡片 mode="style" 时,不支持)
- 修复 thumbnail 不存在仍然占位的 bug
## 1.1.72021-05-12
- 新增 组件示例地址
## 1.1.62021-02-04
- 调整为uni_modules目录规范

@ -0,0 +1,272 @@
<template>
<view class="uni-card" :class="{ 'uni-card--full': isFull, 'uni-card--shadow': isShadow,'uni-card--border':border}"
:style="{'margin':isFull?0:margin,'padding':spacing,'box-shadow':isShadow?shadow:''}">
<!-- 封面 -->
<slot name="cover">
<view v-if="cover" class="uni-card__cover">
<image class="uni-card__cover-image" mode="widthFix" @click="onClick('cover')" :src="cover"></image>
</view>
</slot>
<slot name="title">
<view v-if="title || extra" class="uni-card__header">
<!-- 卡片标题 -->
<view class="uni-card__header-box" @click="onClick('title')">
<view v-if="thumbnail" class="uni-card__header-avatar">
<image class="uni-card__header-avatar-image" :src="thumbnail" mode="aspectFit" />
</view>
<view class="uni-card__header-content">
<text class="uni-card__header-content-title uni-ellipsis">{{ title }}</text>
<text v-if="title&&subTitle"
class="uni-card__header-content-subtitle uni-ellipsis">{{ subTitle }}</text>
</view>
</view>
<view class="uni-card__header-extra" @click="onClick('extra')">
<slot name="extra">
<text class="uni-card__header-extra-text">{{ extra }}</text>
</slot>
</view>
</view>
</slot>
<!-- 卡片内容 -->
<view class="uni-card__content" :style="{padding:padding}" @click="onClick('content')">
<slot></slot>
</view>
<view class="uni-card__actions" @click="onClick('actions')">
<slot name="actions"></slot>
</view>
</view>
</template>
<script>
/**
* Card 卡片
* @description 卡片视图组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=22
* @property {String} title 标题文字
* @property {String} subTitle 副标题
* @property {Number} padding 内容内边距
* @property {Number} margin 卡片外边距
* @property {Number} spacing 卡片内边距
* @property {String} extra 标题额外信息
* @property {String} cover 封面图本地路径需要引入
* @property {String} thumbnail 标题左侧缩略图
* @property {Boolean} is-full = [true | false] 卡片内容是否通栏 true 时将去除padding值
* @property {Boolean} is-shadow = [true | false] 卡片内容是否开启阴影
* @property {String} shadow 卡片阴影
* @property {Boolean} border 卡片边框
* @event {Function} click 点击 Card 触发事件
*/
export default {
name: 'UniCard',
emits: ['click'],
props: {
title: {
type: String,
default: ''
},
subTitle: {
type: String,
default: ''
},
padding: {
type: String,
default: '10px'
},
margin: {
type: String,
default: '15px'
},
spacing: {
type: String,
default: '0 10px'
},
extra: {
type: String,
default: ''
},
cover: {
type: String,
default: ''
},
thumbnail: {
type: String,
default: ''
},
isFull: {
//
type: Boolean,
default: false
},
isShadow: {
//
type: Boolean,
default: true
},
shadow: {
type: String,
default: '0px 0px 3px 1px rgba(0, 0, 0, 0.08)'
},
border: {
type: Boolean,
default: true
}
},
methods: {
onClick(type) {
this.$emit('click', type)
}
}
}
</script>
<style lang="scss">
$uni-border-3: #EBEEF5 !default;
$uni-shadow-base:0 0px 6px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
$uni-main-color: #3a3a3a !default;
$uni-base-color: #6a6a6a !default;
$uni-secondary-color: #909399 !default;
$uni-spacing-sm: 8px !default;
$uni-border-color:$uni-border-3;
$uni-shadow: $uni-shadow-base;
$uni-card-title: 15px;
$uni-cart-title-color:$uni-main-color;
$uni-card-subtitle: 12px;
$uni-cart-subtitle-color:$uni-secondary-color;
$uni-card-spacing: 10px;
$uni-card-content-color: $uni-base-color;
.uni-card {
margin: $uni-card-spacing;
padding: 0 $uni-spacing-sm;
border-radius: 4px;
overflow: hidden;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
background-color: #fff;
flex: 1;
.uni-card__cover {
position: relative;
margin-top: $uni-card-spacing;
flex-direction: row;
overflow: hidden;
border-radius: 4px;
.uni-card__cover-image {
flex: 1;
// width: 100%;
/* #ifndef APP-PLUS */
vertical-align: middle;
/* #endif */
}
}
.uni-card__header {
display: flex;
border-bottom: 1px $uni-border-color solid;
flex-direction: row;
align-items: center;
padding: $uni-card-spacing;
overflow: hidden;
.uni-card__header-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
overflow: hidden;
}
.uni-card__header-avatar {
width: 40px;
height: 40px;
overflow: hidden;
border-radius: 5px;
margin-right: $uni-card-spacing;
.uni-card__header-avatar-image {
flex: 1;
width: 40px;
height: 40px;
}
}
.uni-card__header-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
flex: 1;
// height: 40px;
overflow: hidden;
.uni-card__header-content-title {
font-size: $uni-card-title;
color: $uni-cart-title-color;
// line-height: 22px;
}
.uni-card__header-content-subtitle {
font-size: $uni-card-subtitle;
margin-top: 5px;
color: $uni-cart-subtitle-color;
}
}
.uni-card__header-extra {
line-height: 12px;
.uni-card__header-extra-text {
font-size: 12px;
color: $uni-cart-subtitle-color;
}
}
}
.uni-card__content {
padding: $uni-card-spacing;
font-size: 14px;
color: $uni-card-content-color;
line-height: 22px;
}
.uni-card__actions {
font-size: 12px;
}
}
.uni-card--border {
border: 1px solid $uni-border-color;
}
.uni-card--shadow {
position: relative;
/* #ifndef APP-NVUE */
box-shadow: $uni-shadow;
/* #endif */
}
.uni-card--full {
margin: 0;
border-left-width: 0;
border-left-width: 0;
border-radius: 0;
}
/* #ifndef APP-NVUE */
.uni-card--full:after {
border-radius: 0;
}
/* #endif */
.uni-ellipsis {
/* #ifndef APP-NVUE */
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
/* #endif */
}
</style>

@ -0,0 +1,90 @@
{
"id": "uni-card",
"displayName": "uni-card 卡片",
"version": "1.3.1",
"description": "Card 组件,提供常见的卡片样式。",
"keywords": [
"uni-ui",
"uniui",
"card",
"",
"卡片"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [
"uni-icons",
"uni-scss"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,12 @@
## Card 卡片
> **组件名uni-card**
> 代码块: `uCard`
卡片视图组件。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-card)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

@ -0,0 +1,36 @@
## 1.4.32022-01-25
- 修复 初始化的时候 open 属性失效的bug
## 1.4.22022-01-21
- 修复 微信小程序resize后组件收起的bug
## 1.4.12021-11-22
- 修复 vue3中个别scss变量无法找到的问题
## 1.4.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-collapse](https://uniapp.dcloud.io/component/uniui/uni-collapse)
## 1.3.32021-08-17
- 优化 show-arrow 属性默认为true
## 1.3.22021-08-17
- 新增 show-arrow 属性,控制是否显示右侧箭头
## 1.3.12021-07-30
- 优化 vue3下小程序事件警告的问题
## 1.3.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.2.22021-07-21
- 修复 由1.2.0版本引起的 change 事件返回 undefined 的Bug
## 1.2.12021-07-21
- 优化 组件示例
## 1.2.02021-07-21
- 新增 组件折叠动画
- 新增 value\v-model 属性 ,动态修改面板折叠状态
- 新增 title 插槽 ,可定义面板标题
- 新增 border 属性 ,显示隐藏面板内容分隔线
- 新增 title-border 属性 ,显示隐藏面板标题分隔线
- 修复 resize 方法失效的Bug
- 修复 change 事件返回参数不正确的Bug
- 优化 H5、App 平台自动更具内容更新高度,无需调用 reszie() 方法
## 1.1.72021-05-12
- 新增 组件示例地址
## 1.1.62021-02-05
- 优化 组件引用关系通过uni_modules引用组件
## 1.1.52021-02-05
- 调整为uni_modules目录规范

@ -0,0 +1,402 @@
<template>
<view class="uni-collapse-item">
<!-- onClick(!isOpen) -->
<view @click="onClick(!isOpen)" class="uni-collapse-item__title"
:class="{'is-open':isOpen &&titleBorder === 'auto' ,'uni-collapse-item-border':titleBorder !== 'none'}">
<view class="uni-collapse-item__title-wrap">
<slot name="title">
<view class="uni-collapse-item__title-box" :class="{'is-disabled':disabled}">
<image v-if="thumb" :src="thumb" class="uni-collapse-item__title-img" />
<text class="uni-collapse-item__title-text">{{ title }}</text>
</view>
</slot>
</view>
<view v-if="showArrow"
:class="{ 'uni-collapse-item__title-arrow-active': isOpen, 'uni-collapse-item--animation': showAnimation === true }"
class="uni-collapse-item__title-arrow">
<uni-icons :color="disabled?'#ddd':'#bbb'" size="14" type="bottom" />
</view>
</view>
<view class="uni-collapse-item__wrap" :class="{'is--transition':showAnimation}"
:style="{height: (isOpen?height:0) +'px'}">
<view :id="elId" ref="collapse--hook" class="uni-collapse-item__wrap-content"
:class="{open:isheight,'uni-collapse-item--border':border&&isOpen}">
<slot></slot>
</view>
</view>
</view>
</template>
<script>
// #ifdef APP-NVUE
const dom = weex.requireModule('dom')
// #endif
/**
* CollapseItem 折叠面板子组件
* @description 折叠面板子组件
* @property {String} title 标题文字
* @property {String} thumb 标题左侧缩略图
* @property {String} name 唯一标志符
* @property {Boolean} open = [true|false] 是否展开组件
* @property {Boolean} titleBorder = [true|false] 是否显示标题分隔线
* @property {Boolean} border = [true|false] 是否显示分隔线
* @property {Boolean} disabled = [true|false] 是否展开面板
* @property {Boolean} showAnimation = [true|false] 开启动画
* @property {Boolean} showArrow = [true|false] 是否显示右侧箭头
*/
export default {
name: 'uniCollapseItem',
props: {
//
title: {
type: String,
default: ''
},
name: {
type: [Number, String],
default: ''
},
//
disabled: {
type: Boolean,
default: false
},
// #ifdef APP-PLUS
// ,app
showAnimation: {
type: Boolean,
default: false
},
// #endif
// #ifndef APP-PLUS
//
showAnimation: {
type: Boolean,
default: true
},
// #endif
//
open: {
type: Boolean,
default: false
},
//
thumb: {
type: String,
default: ''
},
// 线
titleBorder: {
type: String,
default: 'auto'
},
border: {
type: Boolean,
default: true
},
showArrow: {
type: Boolean,
default: true
}
},
data() {
// TODO IDbug
const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
return {
isOpen: false,
isheight: null,
height: 0,
elId,
nameSync: 0
}
},
watch: {
open(val) {
this.isOpen = val
this.onClick(val, 'init')
}
},
updated(e) {
this.$nextTick(() => {
this.init(true)
})
},
created() {
this.collapse = this.getCollapse()
this.oldHeight = 0
this.onClick(this.open, 'init')
},
// #ifndef VUE3
// TODO vue2
destroyed() {
if (this.__isUnmounted) return
this.uninstall()
},
// #endif
// #ifdef VUE3
// TODO vue3
unmounted() {
this.__isUnmounted = true
this.uninstall()
},
// #endif
mounted() {
if (!this.collapse) return
if (this.name !== '') {
this.nameSync = this.name
} else {
this.nameSync = this.collapse.childrens.length + ''
}
if (this.collapse.names.indexOf(this.nameSync) === -1) {
this.collapse.names.push(this.nameSync)
} else {
console.warn(`name 值 ${this.nameSync} 重复`);
}
if (this.collapse.childrens.indexOf(this) === -1) {
this.collapse.childrens.push(this)
}
this.init()
},
methods: {
init(type) {
// #ifndef APP-NVUE
this.getCollapseHeight(type)
// #endif
// #ifdef APP-NVUE
this.getNvueHwight(type)
// #endif
},
uninstall() {
if (this.collapse) {
this.collapse.childrens.forEach((item, index) => {
if (item === this) {
this.collapse.childrens.splice(index, 1)
}
})
this.collapse.names.forEach((item, index) => {
if (item === this.nameSync) {
this.collapse.names.splice(index, 1)
}
})
}
},
onClick(isOpen, type) {
if (this.disabled) return
this.isOpen = isOpen
if (this.isOpen && this.collapse) {
this.collapse.setAccordion(this)
}
if (type !== 'init') {
this.collapse.onChange(isOpen, this)
}
},
getCollapseHeight(type, index = 0) {
const views = uni.createSelectorQuery().in(this)
views
.select(`#${this.elId}`)
.fields({
size: true
}, data => {
// TODO
if (index >= 10) return
if (!data) {
index++
this.getCollapseHeight(false, index)
return
}
// #ifdef APP-NVUE
this.height = data.height + 1
// #endif
// #ifndef APP-NVUE
this.height = data.height
// #endif
this.isheight = true
if (type) return
this.onClick(this.isOpen, 'init')
})
.exec()
},
getNvueHwight(type) {
const result = dom.getComponentRect(this.$refs['collapse--hook'], option => {
if (option && option.result && option.size) {
// #ifdef APP-NVUE
this.height = option.size.height + 1
// #endif
// #ifndef APP-NVUE
this.height = option.size.height
// #endif
this.isheight = true
if (type) return
this.onClick(this.open, 'init')
}
})
},
/**
* 获取父元素实例
*/
getCollapse(name = 'uniCollapse') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false;
parentName = parent.$options.name;
}
return parent;
}
}
}
</script>
<style lang="scss">
.uni-collapse-item {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
&__title {
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
box-sizing: border-box;
/* #endif */
flex-direction: row;
align-items: center;
transition: border-bottom-color .3s;
// transition-property: border-bottom-color;
// transition-duration: 5s;
&-wrap {
width: 100%;
flex: 1;
}
&-box {
padding: 0 15px;
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
box-sizing: border-box;
/* #endif */
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 48px;
line-height: 48px;
background-color: #fff;
color: #303133;
font-size: 13px;
font-weight: 500;
/* #ifdef H5 */
cursor: pointer;
outline: none;
/* #endif */
&.is-disabled {
.uni-collapse-item__title-text {
color: #999;
}
}
}
&.uni-collapse-item-border {
border-bottom: 1px solid #ebeef5;
}
&.is-open {
border-bottom-color: transparent;
}
&-img {
height: 22px;
width: 22px;
margin-right: 10px;
}
&-text {
flex: 1;
font-size: 14px;
/* #ifndef APP-NVUE */
white-space: nowrap;
color: inherit;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
/* #endif */
overflow: hidden;
text-overflow: ellipsis;
}
&-arrow {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
margin-right: 10px;
transform: rotate(0deg);
&-active {
transform: rotate(-180deg);
}
}
}
&__wrap {
/* #ifndef APP-NVUE */
will-change: height;
box-sizing: border-box;
/* #endif */
background-color: #fff;
overflow: hidden;
position: relative;
height: 0;
&.is--transition {
// transition: all 0.3s;
transition-property: height, border-bottom-width;
transition-duration: 0.3s;
/* #ifndef APP-NVUE */
will-change: height;
/* #endif */
}
&-content {
position: absolute;
font-size: 13px;
color: #303133;
// transition: height 0.3s;
border-bottom-color: transparent;
border-bottom-style: solid;
border-bottom-width: 0;
&.uni-collapse-item--border {
border-bottom-width: 1px;
border-bottom-color: red;
border-bottom-color: #ebeef5;
}
&.open {
position: relative;
}
}
}
&--animation {
transition-property: transform;
transition-duration: 0.3s;
transition-timing-function: ease;
}
}
</style>

@ -0,0 +1,147 @@
<template>
<view class="uni-collapse">
<slot />
</view>
</template>
<script>
/**
* Collapse 折叠面板
* @description 展示可以折叠 / 展开的内容区域
* @tutorial https://ext.dcloud.net.cn/plugin?id=23
* @property {String|Array} value 当前激活面板改变时触发(如果是手风琴模式参数类型为string否则为array)
* @property {Boolean} accordion = [true|false] 是否开启手风琴效果是否开启手风琴效果
* @event {Function} change 切换面板时触发如果是手风琴模式返回类型为string否则为array
*/
export default {
name: 'uniCollapse',
emits:['change','activeItem','input','update:modelValue'],
props: {
value: {
type: [String, Array],
default: ''
},
modelValue: {
type: [String, Array],
default: ''
},
accordion: {
//
type: [Boolean, String],
default: false
},
},
data() {
return {}
},
computed: {
// TODO vue2 vue3
dataValue() {
let value = (typeof this.value === 'string' && this.value === '') ||
(Array.isArray(this.value) && this.value.length === 0)
let modelValue = (typeof this.modelValue === 'string' && this.modelValue === '') ||
(Array.isArray(this.modelValue) && this.modelValue.length === 0)
if (value) {
return this.modelValue
}
if (modelValue) {
return this.value
}
return this.value
}
},
watch: {
dataValue(val) {
this.setOpen(val)
}
},
created() {
this.childrens = []
this.names = []
},
mounted() {
this.$nextTick(()=>{
this.setOpen(this.dataValue)
})
},
methods: {
setOpen(val) {
let str = typeof val === 'string'
let arr = Array.isArray(val)
this.childrens.forEach((vm, index) => {
if (str) {
if (val === vm.nameSync) {
if (!this.accordion) {
console.warn('accordion 属性为 false ,v-model 类型应该为 array')
return
}
vm.isOpen = true
}
}
if (arr) {
val.forEach(v => {
if (v === vm.nameSync) {
if (this.accordion) {
console.warn('accordion 属性为 true ,v-model 类型应该为 string')
return
}
vm.isOpen = true
}
})
}
})
this.emit(val)
},
setAccordion(self) {
if (!this.accordion) return
this.childrens.forEach((vm, index) => {
if (self !== vm) {
vm.isOpen = false
}
})
},
resize() {
this.childrens.forEach((vm, index) => {
// #ifndef APP-NVUE
vm.getCollapseHeight()
// #endif
// #ifdef APP-NVUE
vm.getNvueHwight()
// #endif
})
},
onChange(isOpen, self) {
let activeItem = []
if (this.accordion) {
activeItem = isOpen ? self.nameSync : ''
} else {
this.childrens.forEach((vm, index) => {
if (vm.isOpen) {
activeItem.push(vm.nameSync)
}
})
}
this.$emit('change', activeItem)
this.emit(activeItem)
},
emit(val){
this.$emit('input', val)
this.$emit('update:modelValue', val)
}
}
}
</script>
<style lang="scss" >
.uni-collapse {
/* #ifndef APP-NVUE */
width: 100%;
display: flex;
/* #endif */
/* #ifdef APP-NVUE */
flex: 1;
/* #endif */
flex-direction: column;
background-color: #fff;
}
</style>

@ -0,0 +1,89 @@
{
"id": "uni-collapse",
"displayName": "uni-collapse 折叠面板",
"version": "1.4.3",
"description": "Collapse 组件,可以折叠 / 展开的内容区域。",
"keywords": [
"uni-ui",
"折叠",
"折叠面板",
"手风琴"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [
"uni-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,12 @@
## Collapse 折叠面板
> **组件名uni-collapse**
> 代码块: `uCollapse`
> 关联组件:`uni-collapse-item`、`uni-icons`。
折叠面板用来折叠/显示过长的内容或者是列表。通常是在多内容分类项使用,折叠不重要的内容,显示重要内容。点击可以展开折叠部分。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-collapse)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

@ -0,0 +1,15 @@
## 1.0.12021-11-23
- 优化 label、label-width 属性
## 1.0.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-combox](https://uniapp.dcloud.io/component/uniui/uni-combox)
## 0.1.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.0.62021-05-12
- 新增 组件示例地址
## 0.0.52021-04-21
- 优化 添加依赖 uni-icons, 导入后自动下载依赖
## 0.0.42021-02-05
- 优化 组件引用关系通过uni_modules引用组件
## 0.0.32021-02-04
- 调整为uni_modules目录规范

@ -0,0 +1,294 @@
<template>
<view class="uni-combox" :class="border ? '' : 'uni-combox__no-border'">
<view v-if="label" class="uni-combox__label" :style="labelStyle">
<text>{{label}}</text>
</view>
<view class="uni-combox__input-box">
<input class="uni-combox__input" type="text" :placeholder="placeholder"
placeholder-class="uni-combox__input-plac" v-model="inputVal" @input="onInput" @focus="onFocus" @blur="onBlur" />
<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
</uni-icons>
</view>
<view class="uni-combox__selector" v-if="showSelector">
<view class="uni-popper__arrow"></view>
<scroll-view scroll-y="true" class="uni-combox__selector-scroll" @scroll="onScroll">
<view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0">
<text>{{emptyTips}}</text>
</view>
<view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index" @click="onSelectorClick(index)">
<text>{{item}}</text>
</view>
</scroll-view>
</view>
<!-- 新增蒙层点击蒙层时关闭选项显示 -->
<view class="uni-combox__mask" v-show="showSelector" @click="showSelector = false"></view>
</view>
</template>
<script>
/**
* Combox 组合输入框
* @description 组合输入框一般用于既可以输入也可以选择的场景
* @tutorial https://ext.dcloud.net.cn/plugin?id=1261
* @property {String} label 左侧文字
* @property {String} labelWidth 左侧内容宽度
* @property {String} placeholder 输入框占位符
* @property {Array} candidates 候选项列表
* @property {String} emptyTips 筛选结果为空时显示的文字
* @property {String} value 组合框的值
*/
export default {
name: 'uniCombox',
emits: ['input', 'update:modelValue'],
props: {
border: {
type: Boolean,
default: true
},
label: {
type: String,
default: ''
},
labelWidth: {
type: String,
default: 'auto'
},
placeholder: {
type: String,
default: ''
},
candidates: {
type: Array,
default () {
return []
}
},
emptyTips: {
type: String,
default: '无匹配项'
},
// #ifndef VUE3
value: {
type: [String, Number],
default: ''
},
// #endif
// #ifdef VUE3
modelValue: {
type: [String, Number],
default: ''
},
// #endif
},
data() {
return {
showSelector: false,
inputVal: '',
blurTimer:null,
}
},
computed: {
labelStyle() {
if (this.labelWidth === 'auto') {
return ""
}
return `width: ${this.labelWidth}`
},
filterCandidates() {
if (this.inputVal !== 0 && !this.inputVal) {
return this.candidates
}
return this.candidates.filter((item) => {
return item.toString().indexOf(this.inputVal) > -1
})
},
filterCandidatesLength() {
return this.filterCandidates.length
}
},
watch: {
// #ifndef VUE3
value: {
handler(newVal) {
this.inputVal = newVal
},
immediate: true
},
// #endif
// #ifdef VUE3
modelValue: {
handler(newVal) {
this.inputVal = newVal
},
immediate: true
},
// #endif
},
methods: {
toggleSelector() {
this.showSelector = !this.showSelector
},
onFocus() {
this.showSelector = true
},
onBlur() {
this.blurTimer = setTimeout(() => {
this.showSelector = false
}, 153)
},
onScroll(){ // blur
if(this.blurTimer) {
clearTimeout(this.blurTimer)
this.blurTimer = null
}
},
onSelectorClick(index) {
this.inputVal = this.filterCandidates[index]
this.showSelector = false
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal)
},
onInput() {
setTimeout(() => {
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal)
})
}
}
}
</script>
<style lang="scss">
.uni-combox {
font-size: 14px;
border: 1px solid #DCDFE6;
border-radius: 4px;
padding: 6px 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
// height: 40px;
flex-direction: row;
align-items: center;
// border-bottom: solid 1px #DDDDDD;
}
.uni-combox__label {
font-size: 16px;
line-height: 22px;
padding-right: 10px;
color: #999999;
}
.uni-combox__input-box {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-combox__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-combox__input-plac {
font-size: 14px;
color: #999;
}
.uni-combox__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
top: calc(100% + 12px);
left: 0;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 3;
padding: 4px 0;
}
.uni-combox__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
.uni-combox__selector-empty,
.uni-combox__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 36px;
font-size: 14px;
text-align: center;
// border-bottom: solid 1px #DDDDDD;
padding: 0px 10px;
}
.uni-combox__selector-item:hover {
background-color: #f9f9f9;
}
.uni-combox__selector-empty:last-child,
.uni-combox__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
// picker
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-combox__no-border {
border: none;
}
.uni-combox__mask {
width:100%;
height:100%;
position: fixed;
top: 0;
left: 0;
z-index: 1;
}
</style>

@ -0,0 +1,90 @@
{
"id": "uni-combox",
"displayName": "uni-combox 组合框",
"version": "1.0.1",
"description": "可以选择也可以输入的表单项 ",
"keywords": [
"uni-ui",
"uniui",
"combox",
"组合框",
"select"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [
"uni-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,11 @@
## Combox 组合框
> **组件名uni-combox**
> 代码块: `uCombox`
组合框组件。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-combox)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

@ -0,0 +1,24 @@
## 1.2.22022-01-19
- 修复 在微信小程序中样式不生效的bug
## 1.2.12022-01-18
- 新增 update 方法 ,在动态更新时间后,刷新组件
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-countdown](https://uniapp.dcloud.io/component/uniui/uni-countdown)
## 1.1.32021-10-18
- 重构
- 新增 font-size 支持自定义字体大小
## 1.1.22021-08-24
- 新增 支持国际化
## 1.1.12021-07-30
- 优化 vue3下小程序事件警告的问题
## 1.1.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.52021-06-18
- 修复 uni-countdown 重复赋值跳两秒的 bug
## 1.0.42021-05-12
- 新增 组件示例地址
## 1.0.32021-05-08
- 修复 uni-countdown 不能控制倒计时的 bug
## 1.0.22021-02-04
- 调整为uni_modules目录规范

@ -0,0 +1,6 @@
{
"uni-countdown.day": "day",
"uni-countdown.h": "h",
"uni-countdown.m": "m",
"uni-countdown.s": "s"
}

@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

@ -0,0 +1,6 @@
{
"uni-countdown.day": "天",
"uni-countdown.h": "时",
"uni-countdown.m": "分",
"uni-countdown.s": "秒"
}

@ -0,0 +1,6 @@
{
"uni-countdown.day": "天",
"uni-countdown.h": "時",
"uni-countdown.m": "分",
"uni-countdown.s": "秒"
}

@ -0,0 +1,267 @@
<template>
<view class="uni-countdown">
<text v-if="showDay" :style="[timeStyle]" class="uni-countdown__number">{{ d }}</text>
<text v-if="showDay" :style="[splitorStyle]" class="uni-countdown__splitor">{{dayText}}</text>
<text :style="[timeStyle]" class="uni-countdown__number">{{ h }}</text>
<text :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : hourText }}</text>
<text :style="[timeStyle]" class="uni-countdown__number">{{ i }}</text>
<text :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : minuteText }}</text>
<text :style="[timeStyle]" class="uni-countdown__number">{{ s }}</text>
<text v-if="!showColon" :style="[splitorStyle]" class="uni-countdown__splitor">{{secondText}}</text>
</view>
</template>
<script>
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index.js'
const {
t
} = initVueI18n(messages)
/**
* Countdown 倒计时
* @description 倒计时组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=25
* @property {String} backgroundColor 背景色
* @property {String} color 文字颜色
* @property {Number} day 天数
* @property {Number} hour 小时
* @property {Number} minute 分钟
* @property {Number} second
* @property {Number} timestamp 时间戳
* @property {Boolean} showDay = [true|false] 是否显示天数
* @property {Boolean} show-colon = [true|false] 是否以冒号为分隔符
* @property {String} splitorColor 分割符号颜色
* @event {Function} timeup 倒计时时间到触发事件
* @example <uni-countdown :day="1" :hour="1" :minute="12" :second="40"></uni-countdown>
*/
export default {
name: 'UniCountdown',
emits: ['timeup'],
props: {
showDay: {
type: Boolean,
default: true
},
showColon: {
type: Boolean,
default: true
},
start: {
type: Boolean,
default: true
},
backgroundColor: {
type: String,
default: ''
},
color: {
type: String,
default: '#333'
},
fontSize: {
type: Number,
default: 14
},
splitorColor: {
type: String,
default: '#333'
},
day: {
type: Number,
default: 0
},
hour: {
type: Number,
default: 0
},
minute: {
type: Number,
default: 0
},
second: {
type: Number,
default: 0
},
timestamp: {
type: Number,
default: 0
},
zeroPad: {
type: Boolean,
default: true
}
},
data() {
return {
timer: null,
syncFlag: false,
d: '00',
h: '00',
i: '00',
s: '00',
leftTime: 0,
seconds: 0
}
},
computed: {
dayText() {
return t("uni-countdown.day")
},
hourText(val) {
return t("uni-countdown.h")
},
minuteText(val) {
return t("uni-countdown.m")
},
secondText(val) {
return t("uni-countdown.s")
},
timeStyle() {
const {
color,
backgroundColor,
fontSize
} = this
return {
color,
backgroundColor,
fontSize: `${fontSize}px`,
width: `${fontSize * 22 / 14}px`, // 14px
lineHeight: `${fontSize * 20 / 14}px`,
borderRadius: `${fontSize * 3 / 14}px`,
}
},
splitorStyle() {
const { splitorColor, fontSize, backgroundColor } = this
return {
color: splitorColor,
fontSize: `${fontSize * 12 / 14}px`,
margin: backgroundColor ? `${fontSize * 4 / 14}px` : ''
}
}
},
watch: {
day(val) {
this.changeFlag()
},
hour(val) {
this.changeFlag()
},
minute(val) {
this.changeFlag()
},
second(val) {
this.changeFlag()
},
start: {
immediate: true,
handler(newVal, oldVal) {
if (newVal) {
this.startData();
} else {
if (!oldVal) return
clearInterval(this.timer)
}
}
}
},
created: function(e) {
this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
this.countDown()
},
// #ifndef VUE3
destroyed() {
clearInterval(this.timer)
},
// #endif
// #ifdef VUE3
unmounted() {
clearInterval(this.timer)
},
// #endif
methods: {
toSeconds(timestamp, day, hours, minutes, seconds) {
if (timestamp) {
return timestamp - parseInt(new Date().getTime() / 1000, 10)
}
return day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds
},
timeUp() {
clearInterval(this.timer)
this.$emit('timeup')
},
countDown() {
let seconds = this.seconds
let [day, hour, minute, second] = [0, 0, 0, 0]
if (seconds > 0) {
day = Math.floor(seconds / (60 * 60 * 24))
hour = Math.floor(seconds / (60 * 60)) - (day * 24)
minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
} else {
this.timeUp()
}
day = (day < 10 && this.zeroPad) ? `0${day}` : day
hour = (hour < 10 && this.zeroPad) ? `0${hour}` : hour
minute = (minute < 10 && this.zeroPad) ? `0${minute}` : minute
second = (second < 10 && this.zeroPad) ? `0${second}` : second
this.d = day
this.h = hour
this.i = minute
this.s = second
},
startData() {
this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
if (this.seconds <= 0) {
this.seconds = this.toSeconds(0, 0, 0, 0, 0)
this.countDown()
return
}
clearInterval(this.timer)
this.countDown()
this.timer = setInterval(() => {
this.seconds--
if (this.seconds < 0) {
this.timeUp()
return
}
this.countDown()
}, 1000)
},
update(){
this.startData();
},
changeFlag() {
if (!this.syncFlag) {
this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
this.startData();
this.syncFlag = true;
}
}
}
}
</script>
<style lang="scss" scoped>
$font-size: 14px;
.uni-countdown {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
&__splitor {
margin: 0 2px;
font-size: $font-size;
color: #333;
}
&__number {
border-radius: 3px;
text-align: center;
font-size: $font-size;
}
}
</style>

@ -0,0 +1,86 @@
{
"id": "uni-countdown",
"displayName": "uni-countdown 倒计时",
"version": "1.2.2",
"description": "CountDown 倒计时组件",
"keywords": [
"uni-ui",
"uniui",
"countdown",
"倒计时"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,10 @@
## CountDown 倒计时
> **组件名uni-countdown**
> 代码块: `uCountDown`
倒计时组件。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-countdown)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

@ -0,0 +1,45 @@
## 1.0.32022-09-16
- 可以使用 uni-scss 控制主题色
## 1.0.22022-06-30
- 优化 在 uni-forms 中的依赖注入方式
## 1.0.12022-02-07
- 修复 multiple 为 true 时v-model 的值为 null 报错的 bug
## 1.0.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
## 0.2.52021-08-23
- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题
## 0.2.42021-08-17
- 修复 单选 list 模式下 icon 为 left 时,选中图标不显示的问题
## 0.2.32021-08-11
- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
## 0.2.22021-07-30
- 优化 在uni-forms组件与label不对齐的问题
## 0.2.12021-07-27
- 修复 单选默认值为0不能选中的Bug
## 0.2.02021-07-13
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.1.112021-07-06
- 优化 删除无用日志
## 0.1.102021-07-05
- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题
## 0.1.92021-07-05
- 修复 nvue 黑框样式问题
## 0.1.82021-06-28
- 修复 selectedTextColor 属性不生效的Bug
## 0.1.72021-06-02
- 新增 map 属性可以方便映射text/value属性
## 0.1.62021-05-26
- 修复 不关联服务空间的情况下组件报错的Bug
## 0.1.52021-05-12
- 新增 组件示例地址
## 0.1.42021-04-09
- 修复 nvue 下无法选中的问题
## 0.1.32021-03-22
- 新增 disabled属性
## 0.1.22021-02-24
- 优化 默认颜色显示
## 0.1.12021-02-24
- 新增 支持nvue
## 0.1.02021-02-18
- “暂无数据”显示居中

@ -0,0 +1,821 @@
<template>
<view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}">
<template v-if="!isLocal">
<view class="uni-data-loading">
<uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18" :content-text="contentText"></uni-load-more>
<text v-else>{{mixinDatacomErrorMessage}}</text>
</view>
</template>
<template v-else>
<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}" @change="chagne">
<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
<checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''" :checked="item.selected" />
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="checkbox__inner" :style="item.styleIcon">
<view class="checkbox__inner-icon"></view>
</view>
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
<view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :style="item.styleBackgroud"></view>
</view>
</label>
</checkbox-group>
<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne">
<!-- -->
<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
<radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''" :checked="item.selected" />
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner"
:style="item.styleBackgroud">
<view class="radio__inner-icon" :style="item.styleIcon"></view>
</view>
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
<view v-if="mode === 'list' && icon === 'right'" :style="item.styleRightIcon" class="checkobx__list"></view>
</view>
</label>
</radio-group>
</template>
</view>
</template>
<script>
/**
* DataChecklist 数据选择器
* @description 通过数据渲染 checkbox radio
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
* @property {String} mode = [default| list | button | tag] 显示模式
* @value default 默认横排模式
* @value list 列表模式
* @value button 按钮模式
* @value tag 标签模式
* @property {Boolean} multiple = [true|false] 是否多选
* @property {Array|String|Number} value 默认值
* @property {Array} localdata 本地数据 格式 [{text:'',value:''}]
* @property {Number|String} min 最小选择个数 multiple为true时生效
* @property {Number|String} max 最大选择个数 multiple为true时生效
* @property {Boolean} wrap 是否换行显示
* @property {String} icon = [left|right] list 列表模式下icon显示位置
* @property {Boolean} selectedColor 选中颜色
* @property {Boolean} emptyText 没有数据时显示的文字 本地数据无效
* @property {Boolean} selectedTextColor 选中文本颜色如不填写则自动显示
* @property {Object} map 字段映射 默认 map={text:'text',value:'value'}
* @value left 左侧显示
* @value right 右侧显示
* @event {Function} change 选中发生变化触发
*/
export default {
name: 'uniDataChecklist',
mixins: [uniCloud.mixinDatacom || {}],
emits:['input','update:modelValue','change'],
props: {
mode: {
type: String,
default: 'default'
},
multiple: {
type: Boolean,
default: false
},
value: {
type: [Array, String, Number],
default () {
return ''
}
},
// TODO vue3
modelValue: {
type: [Array, String, Number],
default() {
return '';
}
},
localdata: {
type: Array,
default () {
return []
}
},
min: {
type: [Number, String],
default: ''
},
max: {
type: [Number, String],
default: ''
},
wrap: {
type: Boolean,
default: false
},
icon: {
type: String,
default: 'left'
},
selectedColor: {
type: String,
default: ''
},
selectedTextColor: {
type: String,
default: ''
},
emptyText:{
type: String,
default: '暂无数据'
},
disabled:{
type: Boolean,
default: false
},
map:{
type: Object,
default(){
return {
text:'text',
value:'value'
}
}
}
},
watch: {
localdata: {
handler(newVal) {
this.range = newVal
this.dataList = this.getDataList(this.getSelectedValue(newVal))
},
deep: true
},
mixinDatacomResData(newVal) {
this.range = newVal
this.dataList = this.getDataList(this.getSelectedValue(newVal))
},
value(newVal) {
this.dataList = this.getDataList(newVal)
// fix by mehaotian is_reset uni-forms
// if(!this.is_reset){
// this.is_reset = false
// this.formItem && this.formItem.setValue(newVal)
// }
},
modelValue(newVal) {
this.dataList = this.getDataList(newVal);
// if(!this.is_reset){
// this.is_reset = false
// this.formItem && this.formItem.setValue(newVal)
// }
}
},
data() {
return {
dataList: [],
range: [],
contentText: {
contentdown: '查看更多',
contentrefresh: '加载中',
contentnomore: '没有更多'
},
isLocal:true,
styles: {
selectedColor: '#2979ff',
selectedTextColor: '#666',
},
isTop:0
};
},
computed:{
dataValue(){
if(this.value === '')return this.modelValue
if(this.modelValue === '') return this.value
return this.value
}
},
created() {
// this.form = this.getForm('uniForms')
// this.formItem = this.getForm('uniFormsItem')
// this.formItem && this.formItem.setValue(this.value)
// if (this.formItem) {
// this.isTop = 6
// if (this.formItem.name) {
// // name,formData
// if(!this.is_reset){
// this.is_reset = false
// this.formItem.setValue(this.dataValue)
// }
// this.rename = this.formItem.name
// this.form.inputChildrens.push(this)
// }
// }
if (this.localdata && this.localdata.length !== 0) {
this.isLocal = true
this.range = this.localdata
this.dataList = this.getDataList(this.getSelectedValue(this.range))
} else {
if (this.collection) {
this.isLocal = false
this.loadData()
}
}
},
methods: {
loadData() {
this.mixinDatacomGet().then(res=>{
this.mixinDatacomResData = res.result.data
if(this.mixinDatacomResData.length === 0){
this.isLocal = false
this.mixinDatacomErrorMessage = this.emptyText
}else{
this.isLocal = true
}
}).catch(err=>{
this.mixinDatacomErrorMessage = err.message
})
},
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false
parentName = parent.$options.name;
}
return parent;
},
chagne(e) {
const values = e.detail.value
let detail = {
value: [],
data: []
}
if (this.multiple) {
this.range.forEach(item => {
if (values.includes(item[this.map.value] + '')) {
detail.value.push(item[this.map.value])
detail.data.push(item)
}
})
} else {
const range = this.range.find(item => (item[this.map.value] + '') === values)
if (range) {
detail = {
value: range[this.map.value],
data: range
}
}
}
// this.formItem && this.formItem.setValue(detail.value)
// TODO vue2
this.$emit('input', detail.value);
// // TOTO vue3
this.$emit('update:modelValue', detail.value);
this.$emit('change', {
detail
})
if (this.multiple) {
// v-model
// if (this.value.length === 0) {
this.dataList = this.getDataList(detail.value, true)
// }
} else {
this.dataList = this.getDataList(detail.value)
}
},
/**
* 获取渲染的新数组
* @param {Object} value 选中内容
*/
getDataList(value) {
//
let dataList = JSON.parse(JSON.stringify(this.range))
let list = []
if (this.multiple) {
if (!Array.isArray(value)) {
value = []
}
}
dataList.forEach((item, index) => {
item.disabled = item.disable || item.disabled || false
if (this.multiple) {
if (value.length > 0) {
let have = value.find(val => val === item[this.map.value])
item.selected = have !== undefined
} else {
item.selected = false
}
} else {
item.selected = value === item[this.map.value]
}
list.push(item)
})
return this.setRange(list)
},
/**
* 处理最大最小值
* @param {Object} list
*/
setRange(list) {
let selectList = list.filter(item => item.selected)
let min = Number(this.min) || 0
let max = Number(this.max) || ''
list.forEach((item, index) => {
if (this.multiple) {
if (selectList.length <= min) {
let have = selectList.find(val => val[this.map.value] === item[this.map.value])
if (have !== undefined) {
item.disabled = true
}
}
if (selectList.length >= max && max !== '') {
let have = selectList.find(val => val[this.map.value] === item[this.map.value])
if (have === undefined) {
item.disabled = true
}
}
}
this.setStyles(item, index)
list[index] = item
})
return list
},
/**
* 设置 class
* @param {Object} item
* @param {Object} index
*/
setStyles(item, index) {
//
item.styleBackgroud = this.setStyleBackgroud(item)
item.styleIcon = this.setStyleIcon(item)
item.styleIconText = this.setStyleIconText(item)
item.styleRightIcon = this.setStyleRightIcon(item)
},
/**
* 获取选中值
* @param {Object} range
*/
getSelectedValue(range) {
if (!this.multiple) return this.dataValue
let selectedArr = []
range.forEach((item) => {
if (item.selected) {
selectedArr.push(item[this.map.value])
}
})
return this.dataValue.length > 0 ? this.dataValue : selectedArr
},
/**
* 设置背景样式
*/
setStyleBackgroud(item) {
let styles = {}
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
if (this.selectedColor) {
if (this.mode !== 'list') {
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
}
if (this.mode === 'tag') {
styles['background-color'] = item.selected? selectedColor:'#f5f5f5'
}
}
let classles = ''
for (let i in styles) {
classles += `${i}:${styles[i]};`
}
return classles
},
setStyleIcon(item) {
let styles = {}
let classles = ''
if (this.selectedColor) {
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
styles['background-color'] = item.selected?selectedColor:'#fff'
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
if(!item.selected && item.disabled){
styles['background-color'] = '#F2F6FC'
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
}
}
for (let i in styles) {
classles += `${i}:${styles[i]};`
}
return classles
},
setStyleIconText(item) {
let styles = {}
let classles = ''
if (this.selectedColor) {
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
if (this.mode === 'tag') {
styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666'
} else {
styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666'
}
if(!item.selected && item.disabled){
styles.color = '#999'
}
}
for (let i in styles) {
classles += `${i}:${styles[i]};`
}
return classles
},
setStyleRightIcon(item) {
let styles = {}
let classles = ''
if (this.mode === 'list') {
styles['border-color'] = item.selected?this.styles.selectedColor:'#DCDFE6'
}
for (let i in styles) {
classles += `${i}:${styles[i]};`
}
return classles
}
}
}
</script>
<style lang="scss">
$uni-primary: #2979ff !default;
$border-color: #DCDFE6;
$disable:0.4;
@mixin flex {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
}
.uni-data-loading {
@include flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 36px;
padding-left: 10px;
color: #999;
}
.uni-data-checklist {
position: relative;
z-index: 0;
flex: 1;
//
.checklist-group {
@include flex;
flex-direction: row;
flex-wrap: wrap;
&.is-list {
flex-direction: column;
}
.checklist-box {
@include flex;
flex-direction: row;
align-items: center;
position: relative;
margin: 5px 0;
margin-right: 25px;
.hidden {
position: absolute;
opacity: 0;
}
//
.checklist-content {
@include flex;
flex: 1;
flex-direction: row;
align-items: center;
justify-content: space-between;
.checklist-text {
font-size: 14px;
color: #666;
margin-left: 5px;
line-height: 14px;
}
.checkobx__list {
border-right-width: 1px;
border-right-color: #007aff;
border-right-style: solid;
border-bottom-width:1px;
border-bottom-color: #007aff;
border-bottom-style: solid;
height: 12px;
width: 6px;
left: -5px;
transform-origin: center;
transform: rotate(45deg);
opacity: 0;
}
}
//
.checkbox__inner {
/* #ifndef APP-NVUE */
flex-shrink: 0;
box-sizing: border-box;
/* #endif */
position: relative;
width: 16px;
height: 16px;
border: 1px solid $border-color;
border-radius: 4px;
background-color: #fff;
z-index: 1;
.checkbox__inner-icon {
position: absolute;
/* #ifdef APP-NVUE */
top: 2px;
/* #endif */
/* #ifndef APP-NVUE */
top: 1px;
/* #endif */
left: 5px;
height: 8px;
width: 4px;
border-right-width: 1px;
border-right-color: #fff;
border-right-style: solid;
border-bottom-width:1px ;
border-bottom-color: #fff;
border-bottom-style: solid;
opacity: 0;
transform-origin: center;
transform: rotate(40deg);
}
}
//
.radio__inner {
@include flex;
/* #ifndef APP-NVUE */
flex-shrink: 0;
box-sizing: border-box;
/* #endif */
justify-content: center;
align-items: center;
position: relative;
width: 16px;
height: 16px;
border: 1px solid $border-color;
border-radius: 16px;
background-color: #fff;
z-index: 1;
.radio__inner-icon {
width: 8px;
height: 8px;
border-radius: 10px;
opacity: 0;
}
}
//
&.is--default {
//
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
.checkbox__inner {
background-color: #F2F6FC;
border-color: $border-color;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.radio__inner {
background-color: #F2F6FC;
border-color: $border-color;
}
.checklist-text {
color: #999;
}
}
//
&.is-checked {
.checkbox__inner {
border-color: $uni-primary;
background-color: $uni-primary;
.checkbox__inner-icon {
opacity: 1;
transform: rotate(45deg);
}
}
.radio__inner {
border-color: $uni-primary;
.radio__inner-icon {
opacity: 1;
background-color: $uni-primary;
}
}
.checklist-text {
color: $uni-primary;
}
//
&.is-disable {
.checkbox__inner {
opacity: $disable;
}
.checklist-text {
opacity: $disable;
}
.radio__inner {
opacity: $disable;
}
}
}
}
//
&.is--button {
margin-right: 10px;
padding: 5px 10px;
border: 1px $border-color solid;
border-radius: 3px;
transition: border-color 0.2s;
//
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
border: 1px #eee solid;
opacity: $disable;
.checkbox__inner {
background-color: #F2F6FC;
border-color: $border-color;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.radio__inner {
background-color: #F2F6FC;
border-color: $border-color;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.checklist-text {
color: #999;
}
}
&.is-checked {
border-color: $uni-primary;
.checkbox__inner {
border-color: $uni-primary;
background-color: $uni-primary;
.checkbox__inner-icon {
opacity: 1;
transform: rotate(45deg);
}
}
.radio__inner {
border-color: $uni-primary;
.radio__inner-icon {
opacity: 1;
background-color: $uni-primary;
}
}
.checklist-text {
color: $uni-primary;
}
//
&.is-disable {
opacity: $disable;
}
}
}
//
&.is--tag {
margin-right: 10px;
padding: 5px 10px;
border: 1px $border-color solid;
border-radius: 3px;
background-color: #f5f5f5;
.checklist-text {
margin: 0;
color: #666;
}
//
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
opacity: $disable;
}
&.is-checked {
background-color: $uni-primary;
border-color: $uni-primary;
.checklist-text {
color: #fff;
}
}
}
//
&.is--list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 10px 15px;
padding-left: 0;
margin: 0;
&.is-list-border {
border-top: 1px #eee solid;
}
//
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
.checkbox__inner {
background-color: #F2F6FC;
border-color: $border-color;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.checklist-text {
color: #999;
}
}
&.is-checked {
.checkbox__inner {
border-color: $uni-primary;
background-color: $uni-primary;
.checkbox__inner-icon {
opacity: 1;
transform: rotate(45deg);
}
}
.radio__inner {
.radio__inner-icon {
opacity: 1;
}
}
.checklist-text {
color: $uni-primary;
}
.checklist-content {
.checkobx__list {
opacity: 1;
border-color: $uni-primary;
}
}
//
&.is-disable {
.checkbox__inner {
opacity: $disable;
}
.checklist-text {
opacity: $disable;
}
}
}
}
}
}
}
</style>

@ -0,0 +1,84 @@
{
"id": "uni-data-checkbox",
"displayName": "uni-data-checkbox 数据选择器",
"version": "1.0.3",
"description": "通过数据驱动的单选框和复选框",
"keywords": [
"uni-ui",
"checkbox",
"单选",
"多选",
"单选多选"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.1.1"
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-load-more","uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,18 @@
## DataCheckbox 数据驱动的单选复选框
> **组件名uni-data-checkbox**
> 代码块: `uDataCheckbox`
本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括
1. 数据绑定型组件给本组件绑定一个data会自动渲染一组候选内容。再以往开发者需要编写不少代码实现类似功能
2. 自动的表单校验组件绑定了data且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验
3. 本组件合并了单选多选
4. 本组件有若干风格选择如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件样式代码虽然不用自己写了却会牺牲一定的样式自定义性
在uniCloud开发中`DB Schema`中配置了enum枚举等类型后在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

@ -0,0 +1,75 @@
## 1.1.22023-04-11
- 修复 更改 modelValue 报错的 bug
- 修复 v-for 未使用 key 值控制台 warning
## 1.1.12023-02-21
- 修复代码合并时引发 value 属性为空时不渲染数据的问题
## 1.1.02023-02-15
- 修复 localdata 不支持动态更新的bug
## 1.0.92023-02-15
- 修复 localdata 不支持动态更新的bug
## 1.0.82022-09-16
- 可以使用 uni-scss 控制主题色
## 1.0.72022-07-06
- 优化 pc端图标位置不正确的问题
## 1.0.62022-07-05
- 优化 显示样式
## 1.0.52022-07-04
- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
## 1.0.42022-04-19
- 修复 字节小程序 本地数据无法选择下一级的Bug
## 1.0.32022-02-25
- 修复 nvue 不支持的 v-show 的 bug
## 1.0.22022-02-25
- 修复 条件编译 nvue 不支持的 css 样式
## 1.0.12021-11-23
- 修复 由上个版本引发的map、v-model等属性不生效的bug
## 1.0.02021-11-19
- 优化 组件 UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
## 0.4.92021-10-28
- 修复 VUE2 v-model 概率无效的 bug
## 0.4.82021-10-27
- 修复 v-model 概率无效的 bug
## 0.4.72021-10-25
- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
## 0.4.62021-10-19
- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
## 0.4.52021-09-26
- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
- 修复 readonly 为 true 时报错的 bug
## 0.4.42021-09-26
- 修复 上一版本造成的 map 属性失效的 bug
- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
## 0.4.32021-09-24
- 修复 某些情况下级联未触发的 bug
## 0.4.22021-09-23
- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
- 新增 选项内容过长自动添加省略号
## 0.4.12021-09-15
- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
## 0.4.02021-07-13
- 组件兼容 vue3如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.3.52021-06-04
- 修复 无法加载云端数据的问题
## 0.3.42021-05-28
- 修复 v-model 无效问题
- 修复 loaddata 为空数据组时加载时间过长问题
- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
## 0.3.32021-05-12
- 新增 组件示例地址
## 0.3.22021-04-22
- 修复 非树形数据有 where 属性查询报错的问题
## 0.3.12021-04-15
- 修复 本地数据概率无法回显时问题
## 0.3.02021-04-07
- 新增 支持云端非树形表结构数据
- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
## 0.2.02021-03-15
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
## 0.1.92021-03-09
- 修复 微信小程序某些情况下无法选择的问题
## 0.1.82021-02-05
- 优化 部分样式在 nvue 上的兼容表现
## 0.1.72021-02-05
- 调整为 uni_modules 目录规范

@ -0,0 +1,45 @@
// #ifdef H5
export default {
name: 'Keypress',
props: {
disable: {
type: Boolean,
default: false
}
},
mounted () {
const keyNames = {
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
space: [' ', 'Spacebar'],
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
delete: ['Backspace', 'Delete', 'Del']
}
const listener = ($event) => {
if (this.disable) {
return
}
const keyName = Object.keys(keyNames).find(key => {
const keyName = $event.key
const value = keyNames[key]
return value === keyName || (Array.isArray(value) && value.includes(keyName))
})
if (keyName) {
// 避免和其他按键事件冲突
setTimeout(() => {
this.$emit(keyName, {})
}, 0)
}
}
document.addEventListener('keyup', listener)
this.$once('hook:beforeDestroy', () => {
document.removeEventListener('keyup', listener)
})
},
render: () => {}
}
// #endif

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save