linwu 1 жил өмнө
parent
commit
9dd16fd812
31 өөрчлөгдсөн 1733 нэмэгдсэн , 5 устгасан
  1. 186 0
      app/admin/controller/Outjob.php
  2. 67 0
      app/admin/view/outjob/dealreport.html
  3. 151 0
      app/admin/view/outjob/index.html
  4. 242 0
      app/admin/view/outjob/recruitform.html
  5. 100 0
      app/admin/view/outjob/report.html
  6. 53 0
      app/common/model/OutRecruit.php
  7. 72 0
      app/common/model/OutRecruitReport.php
  8. 45 0
      app/mobile/controller/Candidate.php
  9. 15 0
      app/mobile/controller/My.php
  10. 106 0
      app/mobile/controller/Recruit.php
  11. 6 0
      app/mobile/controller/Resume.php
  12. 26 0
      app/mobile/validate/CandidateValidate.php
  13. 22 0
      app/mobile/validate/RecruitValidate.php
  14. 127 0
      app/mobile/view/candidate/info.html
  15. 1 1
      app/mobile/view/index/base.html
  16. 18 1
      app/mobile/view/my/index.html
  17. 162 0
      app/mobile/view/recruit/detail.html
  18. 66 0
      app/mobile/view/recruit/index.html
  19. 179 0
      app/mobile/view/recruit/report.html
  20. 15 2
      public/static/mobile/css/style.css
  21. BIN
      public/static/mobile/images/detail_header.jpg
  22. BIN
      public/static/mobile/images/icon_address.png
  23. BIN
      public/static/mobile/images/icon_age.png
  24. BIN
      public/static/mobile/images/icon_num.png
  25. BIN
      public/static/mobile/images/icon_phone_white.png
  26. BIN
      public/static/mobile/images/icon_qrcode.png
  27. BIN
      public/static/mobile/images/icon_salary.png
  28. BIN
      public/static/mobile/images/icon_salary_white.png
  29. BIN
      public/static/mobile/images/icon_volume.png
  30. 63 0
      public/static/mobile/js/components/recruitList.js
  31. 11 1
      public/static/mobile/js/components/resumeList.js

+ 186 - 0
app/admin/controller/Outjob.php

@@ -0,0 +1,186 @@
+<?php
+
+namespace app\admin\controller;
+
+use app\worker\BaseController;
+use app\common\model\OutRecruit as OutRecruitModel;
+use app\common\model\OutRecruitReport as OutRecruitReportModel;
+
+use think\facade\Request;
+
+class Outjob extends BaseController
+{
+    /**
+     * 招聘信息
+     */
+    public function index()
+    {
+        if (Request::isAjax()) {
+            $limit = input('limit/d', 20);
+            $page  = input('page/d', 1);
+
+            $map      = [];
+            $keywords = input('keywords/s', "");
+            if (!empty($keywords)) {
+                $map[] = ['title', 'like', '%' . $keywords . '%'];
+            }
+            $status = input('status/d');
+            if (!empty($status)) {
+                $map[] = ['status', '=', $status];
+            }
+
+            $list  = OutRecruitModel::where($map)
+                ->order(['priority' => 'desc', 'id' => 'desc'])
+                ->limit($limit)
+                ->page($page)
+                ->append(['status_text'])
+                ->select();
+            $count = OutRecruitModel::where($map)->count();
+            if ($count == 0) {
+                exit(json_encode([
+                    'code' => 1,
+                    'msg'  => "未查询到数据",
+                ]));
+            }
+            exit(json_encode([
+                'code'  => 0,
+                'msg'   => "",
+                'count' => $count,
+                'data'  => $list,
+            ]));
+
+        } else {
+            return view('outjob/index');
+        }
+
+    }
+
+    public function recruitform()
+    {
+        $id      = input('id/d, 0');
+        $recruit = OutRecruitModel::findOrEmpty($id);
+
+        return view('outjob/recruitform', [
+            'recruit' => $recruit,
+        ]);
+    }
+
+    public function editrecruit()
+    {
+        $id = input('id/d', 0);
+
+        $data = [
+            'title'        => input('title/s', ""),
+            'company_name' => input('company_name/s', ""),
+            'num'          => input('num/d', 1),
+            'province'     => input('province/s', ""),
+            'city'         => input('city/s', ""),
+            'district'     => input('district/s', ""),
+            'address'      => input('address/s', ""),
+            'agegroup'     => input('agegroup/s', ""),
+            'tags'         => input('tags/a', []),
+            'requirement'  => input('requirement/s', ""),
+            'comdetails'   => input('comdetails/s', ""),
+            'picall'       => input('picall/a', []),
+            'salary'       => input('salary/s', ""),
+            'telephone'    => input('telephone/s', ""),
+            'remark'       => input('remark/s', ""),
+            'status'       => input('status/d', 1),
+            'priority'     => input('priority/d', 255),
+            'volume'       => input('volume/d', 0),
+            'updatetime'   => time(),
+        ];
+
+        if (empty($id)) {
+            $data['createtime'] = time();
+            OutRecruitModel::create($data);
+        } else {
+            OutRecruitModel::update($data, ['id' => $id]);
+        }
+
+        exit(json_encode([
+            'code' => 0,
+        ]));
+    }
+
+    public function delrecruit()
+    {
+        $id = input('id/d');
+
+        $res = OutRecruitReportModel::where('recruit_id', $id)->find();
+        if (!empty($res)) {
+            exit(json_encode([
+                'code' => 1,
+                'msg'  => "已有报备记录,无法删除",
+            ]));
+        }
+
+        OutRecruitModel::destroy($id);
+
+        exit(json_encode([
+            'code' => 0,
+        ]));
+    }
+
+    public function report()
+    {
+        $id = input('id/d', 0);
+        if (Request::isAjax()) {
+            $limit = input('limit/d', 20);
+            $page  = input('page/d', 1);
+
+            $map    = [
+                ['recruit_id', '=', $id],
+            ];
+            $status = input('status/d');
+            if (!empty($status)) {
+                $map[] = ['status', '=', $status];
+            }
+
+            $list  = OutRecruitReportModel::with(['broker'])
+                ->where($map)
+                ->order(['createtime' => 'desc'])
+                ->limit($limit)
+                ->page($page)
+                ->append(['status_text'])
+                ->select();
+            $count = OutRecruitReportModel::where($map)->count();
+            if ($count == 0) {
+                exit(json_encode([
+                    'code' => 1,
+                    'msg'  => "未查询到数据",
+                ]));
+            }
+            exit(json_encode([
+                'code'  => 0,
+                'msg'   => "",
+                'count' => $count,
+                'data'  => $list,
+            ]));
+
+        } else {
+            return view('outjob/report', ['id' => $id]);
+        }
+
+    }
+
+    public function dealreport()
+    {
+        $id = input('id/d', 0);
+        if (Request::isAjax()) {
+            $data = [
+                'status'    => input('status/d', 1),
+                'retremark' => input('retremark/s', ''),
+            ];
+
+            OutRecruitReportModel::update($data, ['id' => $id]);
+
+            exit(json_encode([
+                'code' => 0,
+            ]));
+        } else {
+            $report = OutRecruitReportModel::find($id);
+            return view('outjob/dealreport', ['report' => $report]);
+        }
+    }
+}

+ 67 - 0
app/admin/view/outjob/dealreport.html

@@ -0,0 +1,67 @@
+<div class="layui-fluid">
+	<div class="layui-row layui-col-space15">
+		<div class="layui-col-md12">
+			<div class="layui-card">
+				<div class="layui-card-header">处理报备</div>
+				<div class="layui-card-body" pad15>
+
+					<div class="layui-form layui-form-pane" lay-filter="LAY-outjob-dealreport-edit">
+						<input type="hidden" name="id" value="{$report.id}">
+						<div class="layui-form-item" pane>
+							<label class="layui-form-label">状态</label>
+							<div class="layui-input-block">
+								<input type="radio" name="status" value="1" title="待审核" {eq name="report.status|default=1" value="1"}checked{/eq}>
+								<input type="radio" name="status" value="2" title="待面试" {eq name="report.status" value="2"}checked{/eq}>
+								<input type="radio" name="status" value="3" title="已入职" {eq name="report.status" value="3"}checked{/eq}>
+								<input type="radio" name="status" value="4" title="无效报备" {eq name="report.status" value="4"}checked{/eq}>
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label">反馈备注</label>
+							<div class="layui-input-block">
+								<textarea name="retremark" placeholder="请输入..." class="layui-textarea"></textarea>
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<div class="layui-input-block">
+								<input type="button" lay-submit lay-filter="LAY-outjob-dealreport-edit-submit" value="确认提交" class="layui-btn">
+							</div>
+						</div>
+					</div>
+
+				</div>
+			</div>
+		</div>
+	</div>
+</div>
+
+
+<script>
+	layui.config({
+		base: '/static/echoui/' //静态资源所在路径
+	}).extend({
+		index: 'lib/index' //主入口模块
+	}).use(['index', 'form', 'set'], function() {
+		var $ = layui.$,
+			setter = layui.setter,
+			admin = layui.admin,
+			form = layui.form;
+		form.render();
+
+		form.on('submit(LAY-outjob-dealreport-edit-submit)', function(obj) {
+			var index = parent.layer.getFrameIndex(window.name);
+			admin.req({
+				url: setter.baseAdminUrl + 'outjob/dealreport',
+				data: obj.field,
+				type: 'post',
+				done: function(res) {
+					layer.msg("提交成功", {
+						icon: 1
+					});
+					parent.layui.table.reload('LAY-recruit-report-table'); //重载表格
+					parent.layer.close(index);
+				}
+			});
+		});
+	});
+</script>

+ 151 - 0
app/admin/view/outjob/index.html

@@ -0,0 +1,151 @@
+<div class="layui-fluid">
+	<div class="layui-card">
+		<div class="layui-form layui-form-pane layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-outjob-list-search">
+			<div class="layui-form-item">
+				<div class="layui-inline">
+					<label class="layui-form-label">岗位标题</label>
+					<div class="layui-input-block">
+						<input type="text" name="keywords" placeholder="请输入" autocomplete="off" class="layui-input">
+					</div>
+				</div>
+				<div class="layui-inline">
+					<label class="layui-form-label">状态</label>
+					<div class="layui-input-block">
+						<select name="status">
+							<option value="">全部状态</option>
+							<option value="1">上架</option>
+							<option value="2">下架</option>
+						</select>
+					</div>
+				</div>
+				<div class="layui-inline">
+					<button class="layui-btn" lay-submit lay-filter="LAY-outjob-list-btn">
+						<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
+					</button>
+				</div>
+			</div>
+		</div>
+
+		<div class="layui-card-body">
+			<div style="padding-bottom: 10px;">
+				<button class="layui-btn layuiadmin-btn" data-type="add">添加</button>
+			</div>
+
+			<table id="LAY-outjob-list-table" lay-filter="LAY-outjob-list-table"></table>
+			<script type="text/html" id="setTpl">
+				<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
+				<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
+				<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="report"><i class="layui-icon layui-icon-edit"></i>报备记录</a>
+			</script>
+		</div>
+	</div>
+</div>
+
+<script>
+	layui.config({
+		base: '/static/echoui/' //静态资源所在路径
+	}).extend({
+		index: 'lib/index' //主入口模块
+	}).use(['index', 'form', 'set', 'laydate', 'table'], function() {
+		var $ = layui.$,
+			setter = layui.setter,
+			admin = layui.admin,
+			form = layui.form,
+			table = layui.table;
+		form.render();
+		
+		table.render({
+			elem: '#LAY-outjob-list-table',
+			url: setter.baseAdminUrl + 'outjob/index',
+			cols: [
+				[
+					{ field: 'id', width: 80, title: '表ID', sort: true },
+					{ field: 'title', title: '岗位标题', minWidth: 300},
+					{ field: 'company_name', title: '公司名称', width: 250 },
+					{ field: 'num', title: '招聘人数', width: 100 },
+					{ field: 'province', title: '省', width: 100 },
+					{ field: 'city', title: '市', width: 100 },
+					{ field: 'district', title: '区县', width: 100 },
+					{ field: 'address', title: '地址', width: 100 },
+					{ field: 'agegroup', title: '招工年龄', edit: 'text', width: 120 },
+					{ field: 'salary', title: '工资' },
+					{ field: 'telephone', title: '咨询电话'},
+					{ field: 'status_text', title: '状态', width: 80, align: 'center' },
+					{ field: 'volume', title: '浏览量', width: 100, align: 'right' },
+					{ field: 'priority', width: 100, title: '排序', sort: true},
+					{ title: '操作', width: 250, align: 'center', fixed: 'right', toolbar: '#setTpl' }
+				]
+			],
+			page: true,
+			limit: 50,
+			toolbar: true,
+			cellMinWidth: 150,
+			text: '对不起,加载出现异常!'
+		});
+
+		form.on('submit(LAY-outjob-list-btn)', function(data) {
+			table.reload('LAY-outjob-list-table', {
+				where: data.field,
+				page: {
+					curr: 1
+				}
+			});
+		});
+
+		var active = {
+			add: function() {
+				var index = layer.open({
+					type: 2,
+					title: '添加招聘信息',
+					content: 'recruitform.html?id=0',
+					maxmin: true,
+					area: ['750px', '480px']
+				});
+				layer.full(index);
+			}
+		};
+
+		table.on('tool(LAY-outjob-list-table)', function(obj) {
+			var data = obj.data;
+			if (obj.event === 'del') {
+				layer.confirm('确定删除此招聘信息吗?', function(index) {
+					admin.req({
+						url: setter.baseAdminUrl + 'outjob/delrecruit',
+						data: {
+							id: data.id
+						},
+						done: function(res) {
+							obj.del();
+							layer.msg('已删除');
+						}
+					});
+					layer.close(index);
+				});
+			} else if (obj.event === 'edit') {
+				var index = layer.open({
+					type: 2,
+					title: '编辑招聘信息',
+					content: 'recruitform.html?id=' + data.id,
+					maxmin: true,
+					area: ['750px', '480px']
+				});
+				layer.full(index);
+			}else if (obj.event === 'report') {
+				var index = layer.open({
+					type: 2,
+					title: data.title + '的报备记录',
+					content: 'report.html?id=' + data.id,
+					maxmin: true,
+					area: ['750px', '480px']
+				});
+				layer.full(index);
+			}
+		});
+
+		$('.layui-btn.layuiadmin-btn').on('click', function() {
+			var type = $(this).data('type');
+			active[type] ? active[type].call(this) : '';
+		});
+
+	});
+</script>

+ 242 - 0
app/admin/view/outjob/recruitform.html

@@ -0,0 +1,242 @@
+<div class="layui-fluid">
+	<div class="layui-row layui-col-space15">
+		<div class="layui-col-md12">
+			<div class="layui-card">
+				<div class="layui-card-header">招聘信息</div>
+				<div class="layui-card-body" pad15>
+
+					<div class="layui-form layui-form-pane" lay-filter="LAY-outjob-recruitform-edit">
+						<input type="hidden" name="id" value="{$recruit.id}">
+						<div class="layui-form-item">
+							<label class="layui-form-label"><span style="color:#f90c05;">*</span>订单标题</label>
+							<div class="layui-input-block">
+								<input type="text" name="title" value="{$recruit.title}" lay-verify="required" placeholder="请输入..."
+								 autocomplete="off" class="layui-input">
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label"><span style="color:#f90c05;">*</span>公司名称</label>
+							<div class="layui-input-block">
+								<input type="text" name="company_name" value="{$recruit.company_name}" lay-verify="required" placeholder="请输入..."
+									   autocomplete="off" class="layui-input">
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label">环境照片</label>
+							<div class="layui-input-block">
+								<div class="layui-upload">
+									<button type="button" class="layui-btn attachment-upload-images" data-input="picall" data-amount="9">上传图片</button>
+									<div class="layui-inline layui-word-aux"> 最佳尺寸:750px*375px </div>
+									<div class="layui-upload-list echo-attachment-image-list" id="picall">
+										{volist name="recruit.picall" id="vo"}
+										<div>
+											<input type="hidden" name="picall[]" value="{$vo}">
+											<img src="{$vo}"> <button type="button" class="attachmentdel layui-btn layui-btn-primary layui-btn-xs layui-btn-fluid">删除</button>
+										</div>
+										{/volist}
+									</div>
+								</div>
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label"><span style="color:#f90c05;">*</span>招聘人数</label>
+							<div class="layui-input-block">
+								<input type="text" name="num" value="{$recruit.num|default=1}" lay-verify="number" placeholder="请输入..."
+									   autocomplete="off" class="layui-input">
+							</div>
+						</div>
+						<div class="layui-form-item" id="LAY-areapicker">
+							<label class="layui-form-label"><span style="color:#f90c05;">*</span>省市区</label>
+							<div class="layui-input-inline">
+								<select name="province" class="province-selector" data-value="{$recruit.province}" lay-filter="province-2"
+								 lay-verify="required">
+									<option value="">请选择省</option>
+								</select>
+							</div>
+							<div class="layui-input-inline">
+								<select name="city" class="city-selector" data-value="{$recruit.city}" lay-filter="city-2" lay-verify="required">
+									<option value="">请选择市</option>
+								</select>
+							</div>
+							<div class="layui-input-inline">
+								<select name="district" class="district-selector" data-value="{$recruit.district}" lay-filter="district-2"
+								 lay-verify="required">
+									<option value="">请选择区</option>
+								</select>
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label"><span style="color:#f90c05;">*</span>地址</label>
+							<div class="layui-input-block">
+								<input type="text" name="address" value="{$recruit.address}" lay-verify="required" placeholder="请输入..."
+									   autocomplete="off" class="layui-input">
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label"><span style="color:#f90c05;">*</span>招工年龄</label>
+							<div class="layui-input-block">
+								<input type="text" name="agegroup" value="{$recruit.agegroup}" lay-verify="required" placeholder="18岁到60岁"
+								 autocomplete="off" class="layui-input">
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label">招聘标签</label>
+							<div class="layui-input-block">
+								<div class="tags" id="tags">
+									<input type="text" name="" id="inputTags" placeholder="回车生成标签" autocomplete="off">
+								</div>
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label">岗位要求</label>
+							<div class="layui-input-block">
+								<textarea name="requirement" placeholder="请输入..." rows="6" class="layui-textarea">{$recruit.requirement}</textarea>
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label">企业简介</label>
+							<div class="layui-input-block">
+								<textarea name="comdetails" placeholder="请输入..." rows="6" class="layui-textarea">{$recruit.comdetails}</textarea>
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label">工资</label>
+							<div class="layui-input-block">
+								<input type="text" name="salary" value="{$recruit.salary}" placeholder="5000/月"
+								 autocomplete="off" class="layui-input">
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label"><span style="color:#f90c05;">*</span>咨询电话</label>
+							<div class="layui-input-block">
+								<input type="text" name="telephone" value="{$recruit.telephone}" lay-verify="required" placeholder="请输入..." autocomplete="off" class="layui-input">
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label">补充说明</label>
+							<div class="layui-input-block">
+								<textarea name="remark" placeholder="请输入..." class="layui-textarea">{$recruit.remark}</textarea>
+							</div>
+						</div>
+						<div class="layui-form-item" pane>
+							<label class="layui-form-label">状态</label>
+							<div class="layui-input-block">
+								<input type="radio" name="status" value="1" title="上架" {eq name="recruit.status|default=1" value="1"}checked{/eq}>
+								<input type="radio" name="status" value="2" title="下架" {eq name="recruit.status" value="2"}checked{/eq}>
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label">推荐</label>
+							<div class="layui-input-block">
+								<input type="text" name="priority" value="{$recruit.priority|default=255}" lay-verify="required" placeholder="请输入..." autocomplete="off" class="layui-input">
+								<div class="layui-form-mid layui-word-aux">推荐值值越大越靠前</div>
+							</div>
+						</div>
+						<div class="layui-form-item">
+							<label class="layui-form-label">浏览量</label>
+							<div class="layui-input-block">
+								<input type="text" name="volume" value="{$recruit.volume|default=0}" lay-verify="number" placeholder="请输入..."
+								 autocomplete="off" class="layui-input">
+							</div>
+						</div>
+
+						<div class="layui-form-item">
+							<div class="layui-input-block">
+								<input type="button" lay-submit lay-filter="LAY-outjob-recruitform-edit-submit" value="确认提交" class="layui-btn">
+							</div>
+						</div>
+					</div>
+
+				</div>
+			</div>
+		</div>
+	</div>
+</div>
+
+
+<script>
+	layui.config({
+		base: '/static/echoui/' //静态资源所在路径
+	}).extend({
+		index: 'lib/index' //主入口模块
+	}).use(['index', 'form', 'set', 'upload', 'inputTags', 'layarea'], function() {
+		var $ = layui.$,
+			setter = layui.setter,
+			admin = layui.admin,
+			form = layui.form,
+			inputTags = layui.inputTags,
+			upload = layui.upload,
+			layarea = layui.layarea;
+		form.render();
+
+		inputTags.render({
+			elem: '#inputTags',
+			content: {:json_encode($recruit.tags)} == null ? [] : {:json_encode($recruit.tags)},
+			aldaBtn: true,
+			count: 6,
+			done: function(value) {}
+		});
+		
+		layarea.render({
+			elem: '#LAY-areapicker',
+			data: {
+                province: '福建省',
+                city: '泉州市',
+                district: '晋江市',
+			}
+		});
+
+		$('.echo-attachment-image-list').on('click', '.attachmentdel', function() {
+			$(this).parent().remove();
+		});
+		upload.render({
+			elem: '.attachment-upload-images',
+			url: setter.baseAdminUrl + 'attachment/tplfieldimage',
+			accept: 'images',
+			exits: 'jpg|png|jpeg',
+			acceptMime: 'image/*',
+			size: 2048,
+			number: 1,
+			method: 'post',
+			before: function(obj) {
+				var item = this.item;
+				upload_input = $(item).data('input');
+				upload_amount = $(item).data('amount');
+				layer.load();
+			},
+			done: function(res, index, upload) {
+				layer.closeAll('loading');
+				var html = "";
+				if (upload_amount == 1) {
+					html += '<div> <input type="hidden" name="' + upload_input + '" value="' + res.data.src + '"> ';
+					html += '<img src="' + res.data.src + '"></div>';
+					$("#" + upload_input).html(html);
+				} else {
+					html += '<div> <input type="hidden" name="' + upload_input + '[]" value="' + res.data.src + '"> ';
+					html += '<img src="' + res.data.src +
+							'"> <button type="button" class="attachmentdel layui-btn layui-btn-primary layui-btn-xs layui-btn-fluid">删除</button></div>';
+					$("#" + upload_input).append(html);
+				}
+			},
+			error: function(index, upload) {
+				layer.closeAll('loading');
+			}
+		});
+
+		form.on('submit(LAY-outjob-recruitform-edit-submit)', function(obj) {
+			var index = parent.layer.getFrameIndex(window.name);
+			admin.req({
+				url: setter.baseAdminUrl + 'outjob/editrecruit',
+				data: obj.field,
+				type: 'post',
+				done: function(res) {
+					layer.msg("提交成功", {
+						icon: 1
+					});
+					parent.layui.table.reload('LAY-outjob-list-table'); //重载表格
+					parent.layer.close(index);
+				}
+			});
+		});
+	});
+</script>

+ 100 - 0
app/admin/view/outjob/report.html

@@ -0,0 +1,100 @@
+<div class="layui-fluid">
+	<div class="layui-card">
+		<div class="layui-form layui-form-pane layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-recruit-report-search">
+			<div class="layui-form-item">
+				<div class="layui-inline">
+					<label class="layui-form-label">状态</label>
+					<div class="layui-input-block">
+						<select name="status">
+							<option value="">全部状态</option>
+							<option value="1">待审核</option>
+							<option value="2">待面试</option>
+							<option value="3">已入职</option>
+							<option value="4">无效报备</option>
+						</select>
+					</div>
+				</div>
+				<div class="layui-inline">
+					<button class="layui-btn" lay-submit lay-filter="LAY-recruit-report-btn">
+						<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
+					</button>
+				</div>
+			</div>
+		</div>
+
+		<div class="layui-card-body">
+			<table id="LAY-recruit-report-table" lay-filter="LAY-recruit-report-table"></table>
+			<script type="text/html" id="broker">
+				{{d.broker.title}}({{d.broker.mobile}})
+			</script>
+			<script type="text/html" id="setTpl">
+				<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="deal"><i class="layui-icon layui-icon-edit"></i>处理</a>
+			</script>
+		</div>
+	</div>
+</div>
+
+<script>
+	layui.config({
+		base: '/static/echoui/' //静态资源所在路径
+	}).extend({
+		index: 'lib/index' //主入口模块
+	}).use(['index', 'form', 'set', 'table'], function() {
+		var $ = layui.$,
+			setter = layui.setter,
+			form = layui.form,
+			table = layui.table;
+
+		form.render();
+
+		table.render({
+			elem: '#LAY-recruit-report-table',
+			height: 'full-20',
+			url: setter.baseAdminUrl + 'outjob/report?id={$id}',
+			cols: [
+				[
+					{ field: 'id', width: 80, title: '表ID', sort: true },
+					{ field: 'brokerid', align: 'center', title: '经纪人', minWidth: 200, toolbar: '#broker' },
+					{ field: 'realname', title: '姓名', width: 100 },
+					{ field: 'mobile', title: '手机号', width: 120 },
+					{ field: 'idcard', title: '身份证号', width: 180 },
+					{ field: 'arrivetime', title: '预计到达时间', width: 150 },
+					{ field: 'status_text', title: '状态', width: 100 },
+					{ field: 'createtime', title: '报备时间', width: 150 },
+					{ field: 'remark', title: '备注信息'},
+					{ field: 'retremark', title: '反馈备注信息'},
+					{ title: '操作', width: 100, align: 'center', fixed: 'right', toolbar: '#setTpl' }
+				]
+			],
+			page: true,
+			limit: 50,
+			toolbar: true,
+			cellMinWidth: 150,
+			text: '对不起,加载出现异常!'
+		});
+
+		form.on('submit(LAY-recruit-report-btn)', function(data) {
+			table.reload('LAY-recruit-report-table', {
+				where: data.field,
+				page: {
+					curr: 1
+				}
+			});
+		});
+
+		table.on('tool(LAY-recruit-report-table)', function(obj) {
+			var data = obj.data;
+			if (obj.event === 'deal') {
+				var index = layer.open({
+					type: 2,
+					title: '编辑招聘信息',
+					content: 'dealreport?id=' + data.id,
+					maxmin: true,
+					area: ['650px', '400px']
+				});
+			}
+		});
+
+
+	});
+</script>

+ 53 - 0
app/common/model/OutRecruit.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace app\common\model;
+
+use think\Model;
+
+class OutRecruit extends Model
+{
+
+    // 设置字段信息
+    protected $schema = [
+        'id'           => 'int',
+        'title'        => 'string',
+        'company_name' => 'string',
+        'num'          => 'int',
+
+        'province' => 'string',
+        'city'     => 'string',
+        'district' => 'string',
+        'address'  => 'string',
+
+        'agegroup'    => 'string',
+        'tags'        => 'string',
+        'requirement' => 'string',
+        'comdetails'  => 'string',
+        'picall'      => 'string',
+
+        'salary'     => 'string',
+        'telephone'  => 'string',
+        'remark'     => 'string',
+        'status'     => 'tinyint',
+        'priority'   => 'int',
+        'updatetime' => 'int',
+        'createtime' => 'int',
+        'volume'     => 'int',
+    ];
+
+    // 设置字段自动转换类型
+    protected $type = [
+        'tags'       => 'json',
+        'picall'     => 'json',
+        'updatetime' => 'timestamp:Y-m-d H:i:s',
+        'createtime' => 'timestamp:Y-m-d H:i:s',
+    ];
+    // 设置JSON数据返回数组
+    protected $jsonAssoc = true;
+
+    public function getStatusTextAttr($value, $data)
+    {
+        $status = [1 => '上架', 2 => '下架'];
+        return $status[$data['status']];
+    }
+}

+ 72 - 0
app/common/model/OutRecruitReport.php

@@ -0,0 +1,72 @@
+<?php
+
+namespace app\common\model;
+
+use think\Model;
+
+class OutRecruitReport extends Model
+{
+    // 设置字段信息
+    protected $schema = [
+        'id'         => 'int',
+        'recruit_id' => 'int',
+        'workerid'   => 'int',
+        'agentid'    => 'int',
+        'brokerid'   => 'int',
+        'realname'   => 'string',
+        'mobile'     => 'string',
+        'idcard'     => 'string',
+        'arrivetime' => 'string',
+        'status'     => 'tinyint',
+        'remark'     => 'string',
+        'retremark'  => 'string',
+        'createtime' => 'int',
+    ];
+
+    // 设置字段自动转换类型
+    protected $type = [
+        'createtime' => 'timestamp:Y-m-d H:i',
+    ];
+
+    public function getStatusTextAttr($value, $data)
+    {
+        $status = [1 => '待审核', 2 => '待面试', 3 => '已入职', 4 => '无效报备'];
+        return $status[$data['status']];
+    }
+
+    public function getAgeTextAttr($value, $data)
+    {
+        $year     = substr($data['idcard'], 6, 4);
+        $monthDay = substr($data['idcard'], 10, 4);
+        $age      = date('Y') - $year;
+        if ($monthDay > date('md')) {
+            $age--;
+        }
+        return $age;
+    }
+
+    // 关联Comjobs
+    public function recruit()
+    {
+        return $this->hasOne(OutRecruit::class, "id", "recruit_id");
+    }
+
+    // 关联Agent
+    public function worker()
+    {
+        return $this->hasOne(Worker::class, "id", "agentid");
+    }
+
+    // 关联Agent
+    public function agent()
+    {
+        return $this->hasOne(Agent::class, "id", "agentid");
+    }
+
+    // 关联Broker
+    public function broker()
+    {
+        return $this->hasOne(Broker::class, "id", "brokerid");
+    }
+
+}

+ 45 - 0
app/mobile/controller/Candidate.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace app\mobile\controller;
+
+use app\common\model\Broker as BrokerModel;
+use app\common\model\OutResume as OutResumeModel;
+use app\mobile\MobileBaseController;
+use app\mobile\validate\CandidateValidate;
+use think\exception\ValidateException;
+
+class Candidate extends MobileBaseController
+{
+    public function info()
+    {
+        $broker_id = input('get.broker_id');
+        empty($broker_id) && jump('无法获取经纪人信息');
+
+        $broker = BrokerModel::where('id', $broker_id)->find();
+        empty($broker) && jump('无法获取经纪人信息');
+        $broker['type'] != 3 && jump('无法获取经纪人信息');
+
+        return view('candidate/info', ['broker' => $broker]);
+    }
+
+    public function infoPost()
+    {
+        $data = input('post.');
+        try {
+            validate(CandidateValidate::class)->check($data);
+        } catch (ValidateException $e) {
+            ajax_return(1, $e->getError());
+        }
+
+        $idcard_check = OutResumeModel::where('idcard', $data['idcard'])->find();
+        $idcard_check && ajax_return(1, '该身份证号已被登记!');
+
+        $mobile_check = OutResumeModel::where('mobile', $data['mobile'])->find();
+        $mobile_check && ajax_return(1, '该手机号已被登记!');
+
+        $data['updatetime'] = $data['createtime'] = time();
+        OutResumeModel::create($data);
+
+        ajax_return();
+    }
+}

+ 15 - 0
app/mobile/controller/My.php

@@ -58,4 +58,19 @@ class My extends MobileBaseController
 
         ajax_success($list);
     }
+
+    /**
+     * 推广码
+     */
+    public function qrcode()
+    {
+        error_reporting(E_ERROR);
+        $url = request()->domain(true) . '/mobile/candidate/info?broker_id=' . $this->_broker['id'];
+        header('Content-Type: image/png');
+        ob_clean();
+        $errorCorrectionLevel = "L"; // 纠错级别:L、M、Q、H
+        $matrixPointSize      = "4"; //生成图片大小 :1到10
+        \phpqrcode\QRcode::png($url, false, $errorCorrectionLevel, $matrixPointSize);
+        exit();
+    }
 }

+ 106 - 0
app/mobile/controller/Recruit.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace app\mobile\controller;
+
+use app\common\model\OutRecruit as OutRecruitModel;
+use app\common\model\OutRecruitReport;
+use app\mobile\MobileBaseController;
+use app\mobile\validate\RecruitValidate;
+use think\App;
+use think\exception\ValidateException;
+use think\facade\View;
+
+class Recruit extends MobileBaseController
+{
+    private $_broker = null;
+
+    public function __construct(App $app)
+    {
+        parent::__construct($app);
+        $this->_broker = get_broker();
+        View::assign('broker', $this->_broker);
+    }
+
+    /**
+     * 招聘信息
+     */
+    public function index()
+    {
+        return view('recruit/index');
+    }
+
+    /**
+     * 招聘信息列表
+     */
+    public function listRecruit()
+    {
+        $map   = $this->dealLikeInput(['keyword' => 'title|company_name']);
+        $map[] = ['status', '=', 1];
+
+        $list = OutRecruitModel::where($map)
+            ->order(['id' => 'desc'])
+            ->limit(input('limit', 10))
+            ->page(input('page', 1))
+            ->select();
+
+        ajax_success($list);
+    }
+
+    /**
+     * 详情
+     */
+    public function detail()
+    {
+        $id = input('id/d', 0);
+
+        $info = OutRecruitModel::find($id);
+        if (empty($info) || $info['status'] != 1) {
+            jump('该信息不存在或已下架');
+        }
+
+        return view('recruit/detail', ['info' => $info]);
+    }
+
+    /**
+     * 报备
+     */
+    public function report()
+    {
+        $id = input('id/d', 0);
+
+        $info = OutRecruitModel::find($id);
+        if (empty($info) || $info['status'] != 1) {
+            jump('该信息不存在或已下架');
+        }
+
+        return view('recruit/report', ['info' => $info]);
+    }
+
+    /**
+     * 报备提交
+     */
+    public function reportPost()
+    {
+        $data = input('post.');
+        try {
+            validate(RecruitValidate::class)->check($data);
+        } catch (ValidateException $e) {
+            ajax_return(1, $e->getError());
+        }
+
+        $idcard_check = OutRecruitReport::where('idcard', $data['idcard'])->where('recruit_id', $data['recruit_id'])->find();
+        $idcard_check && ajax_return(1, '该身份证号已报备,请勿重复报备!');
+
+        $mobile_check = OutRecruitReport::where('mobile', $data['mobile'])->where('recruit_id', $data['recruit_id'])->find();
+        $mobile_check && ajax_return(1, '该手机号已报备,请勿重复报备!');
+
+        $data['workerid']   = $this->_broker['workerid'];
+        $data['agentid']    = $this->_broker['agentid'];
+        $data['brokerid']   = $this->_broker['id'];
+        $data['createtime'] = time();
+
+        OutRecruitReport::create($data);
+
+        ajax_return();
+    }
+}

+ 6 - 0
app/mobile/controller/Resume.php

@@ -90,6 +90,12 @@ class Resume extends MobileBaseController
             ajax_return(1, $e->getError());
         }
 
+        $idcard_check = OutResumeModel::where('idcard', $data['idcard'])->find();
+        $idcard_check && ajax_return(1, '该身份证号已被登记!');
+
+        $mobile_check = OutResumeModel::where('mobile', $data['mobile'])->find();
+        $mobile_check && ajax_return(1, '该手机号已被登记!');
+
         $data['brokerid']   = $this->_broker['id'];
         $data['updatetime'] = time();
 

+ 26 - 0
app/mobile/validate/CandidateValidate.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace app\mobile\validate;
+
+use think\Validate;
+
+class CandidateValidate extends Validate
+{
+    protected $rule = [
+        'name'      => 'require',
+        'brokerid' => 'require',
+        'mobile'    => 'require|mobile',
+        'idcard'    => 'require|idCard',
+        'gender'    => 'require',
+        'age'       => 'require|number',
+    ];
+
+    protected $message = [
+        'name'      => '请选择姓名',
+        'brokerid' => '经纪人不能为空',
+        'mobile'    => '手机号格式不对',
+        'idcard'    => '身份证号格式不对',
+        'gender'    => '请选择性别',
+        'age'       => '年龄格式不对',
+    ];
+}

+ 22 - 0
app/mobile/validate/RecruitValidate.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace app\mobile\validate;
+
+use think\Validate;
+
+class RecruitValidate extends Validate
+{
+    protected $rule = [
+        'realname'   => 'require',
+        'mobile'     => 'require|mobile',
+        'idcard'     => 'require|idCard',
+        'arrivetime' => 'require',
+    ];
+
+    protected $message = [
+        'name'       => '请填写姓名',
+        'mobile'     => '手机号格式不对',
+        'idcard'     => '身份证号格式不对',
+        'arrivetime' => '请选择出发日期',
+    ];
+}

+ 127 - 0
app/mobile/view/candidate/info.html

@@ -0,0 +1,127 @@
+{extend name="public/base"/}
+{block name="css"}
+
+{/block}
+{block name="body"}
+<van-nav-bar
+        class="nav-theme"
+        :fixed="true"
+        :placeholder="true"
+>
+    <template #title>
+        <span class="text-white">简历</span>
+    </template>
+</van-nav-bar>
+<van-form @submit="onSubmit">
+    <div class="lw-title">基础信息</div>
+    <van-cell-group inset>
+        <van-field
+                v-model="form.name"
+                required
+                label="姓名"
+                placeholder="请填写姓名"
+                :rules="[{ required: true, message: '请填写姓名' }]"
+        ></van-field>
+        <van-field required name="gender" label="性别">
+            <template #input>
+                <van-radio-group v-model="form.gender" direction="horizontal">
+                    <van-radio :name="1">男</van-radio>
+                    <van-radio :name="2">女</van-radio>
+                </van-radio-group>
+            </template>
+        </van-field>
+        <van-field
+                v-model="form.mobile"
+                required
+                label="手机号"
+                placeholder="请填写手机号"
+                :rules="[
+                        { required: true, message: '请填写手机号' },
+                        { validator, message: '请输入正确的手机号'}
+                    ]"
+        ></van-field>
+        <van-field
+                v-model="form.idcard"
+                required
+                label="身份证"
+                placeholder="请填写身份证号"
+                :rules="[{ required: true, message: '请填写身份证号' }]"
+        ></van-field>
+        <van-field
+                v-model="form.age"
+                type="digit"
+                required
+                label="年龄"
+                placeholder="请填写年龄"
+                :rules="[{ required: true, message: '请填写年龄' }]"
+        ></van-field>
+    </van-cell-group>
+
+    <div class="lw-title">求职信息</div>
+    <van-cell-group inset>
+        <van-field
+                v-model="form.jobintention"
+                label="求职意向"
+                placeholder="请填写求职意向"
+        ></van-field>
+        <van-field
+                v-model="form.address"
+                label="地址"
+                placeholder="请填写地址"
+        ></van-field>
+        <van-field
+                v-model="form.education"
+                label="学历"
+                placeholder="请填写学历"
+        ></van-field>
+        <van-field
+                v-model="form.comment"
+                rows="2"
+                autosize
+                label="备注"
+                type="textarea"
+                maxlength="1000"
+                placeholder="请输入备注"
+                show-word-limit
+        ></van-field>
+    </van-cell-group>
+    <div style="margin: 16px;">
+        <van-button round block type="primary" native-type="submit">
+            提交
+        </van-button>
+    </div>
+</van-form>
+{/block}
+{block name="script"}
+<script>
+    function v_setup() {
+        let base = {};
+
+        //表单
+        base.form = Vue.reactive({
+            name: '',
+            mobile: '',
+            gender: 1,
+            idcard: '',
+            age: '',
+            jobintention: '',
+            address: '',
+            education: '',
+            brokerid: {$broker.id},
+        });
+        base.onSubmit = () => {
+            postJson("{:url('candidate/infoPost')}", base.form).then(({data}) => {
+                vant.showToast('提交成功');
+            });
+        };
+
+        //手机号验证
+        base.validator = (val) => {
+            return /^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$/.test(val);
+        };
+
+
+        return base;
+    }
+</script>
+{/block}

+ 1 - 1
app/mobile/view/index/base.html

@@ -15,7 +15,7 @@
         <span class="text-white">首页</span>
     </template>
 </van-nav-bar>
-<van-tabbar v-model="active" @change="onTab" :placeholder="true">
+<van-tabbar v-model="active" @change="onTab">
     <van-tabbar-item icon="wap-home-o">首页</van-tabbar-item>
     <van-tabbar-item icon="description">文章</van-tabbar-item>
     <van-tabbar-item icon="user-circle-o">我的</van-tabbar-item>

+ 18 - 1
app/mobile/view/my/index.html

@@ -4,6 +4,7 @@
     .van-grid .van-grid-item .price {font-size:25px;color: #e54d42;}
     .van-grid .van-grid-item .price-title {font-size:16px;color: #aaaaaa;}
     .van-grid .van-grid-item .van-badge__wrapper {text-align:center;}
+    .van-image-preview__swipe {background:#333;}
 </style>
 {/block}
 {block name="body"}
@@ -44,7 +45,7 @@
 
 <div style="width:100%;height:30px;"></div>
 <van-grid clickable :column-num="3">
-    <van-grid-item text="招聘信息">
+    <van-grid-item text="招聘信息" url="/mobile/recruit/index">
         <template #icon>
             <van-image
                     width="50%"
@@ -68,6 +69,14 @@
             ></van-image>
         </template>
     </van-grid-item>
+    <van-grid-item text="我的推广码" @click="showQrcode">
+        <template #icon>
+            <van-image
+                    width="50%"
+                    src="__MIMAGES__/icon_qrcode.png"
+            ></van-image>
+        </template>
+    </van-grid-item>
 </van-grid>
 {/block}
 {block name="script"}
@@ -77,6 +86,14 @@
 
         base.broker = {$broker};
 
+        base.showQrcode = () => {
+            vant.showImagePreview({
+                images:['{:url("/mobile/my/qrcode")}'],
+                showIndex: false,
+                loop:false,
+            });
+        };
+
         return base;
     }
 </script>

+ 162 - 0
app/mobile/view/recruit/detail.html

@@ -0,0 +1,162 @@
+{extend name="public/base"/}
+{block name="css"}
+<style>
+    .base-content .header {background-image:url("__MIMAGES__/detail_header.jpg");background-repeat:no-repeat;background-size:100% 70px;width:100%;height:70px;display:flex;align-items:center;justify-content:center;padding:0 20px;}
+    .base-content .header .left {flex:1;display:flex;flex-direction:column;}
+    .base-content .header .salary-box {line-height:24px;height:24px;flex:1;}
+    .base-content .header .salary-box .salary {color:white;font-size:24px;font-weight:bold;}
+    .base-content .header .salary-box .text {color:white;font-size:14px;margin-left:5px;}
+    .base-content .header .company-name {color:white;font-size:14px;}
+    .base-content .header .phone-box {display:flex;flex-direction:column;}
+    .base-content .header .phone-box .text{color:white;}
+    .base-content .title {background:white;padding:10px 20px;color:#000;font-size:18px;}
+    .base-content .tags {background:white;padding:0 20px 10px 20px;}
+    .base-content .tags .van-tag {margin-right:5px;}
+    .base-content .introduce {background:white;}
+    .base-content .introduce .introduce-item {border-top:1px solid #f0f0f0;padding:5px 20px;display:flex;align-items:center;}
+    .base-content .introduce .introduce-item .van-image{margin-right:5px;}
+    .base-content .introduce .introduce-item .split{margin:0 15px;}
+    .describe {margin-top:10px;background:white;}
+    .describe .header {padding:10px 20px;font-size:16px;border-bottom:1px solid #f0f0f0;}
+    .describe .content {padding:10px 20px;}
+    .describe .content pre {font-size: 14px;line-height: 20px;padding: 0;margin: 0;font-family: "Microsoft Yahei",arial,"Hiragino Sans GB","Hiragino Sans GB W3",宋体,simsun;}
+</style>
+{/block}
+{block name="body"}
+<van-nav-bar
+        class="nav-theme"
+        :fixed="true"
+        :placeholder="true"
+        left-text="返回"
+        left-arrow
+        @click-left="onBack"
+>
+    <template #title>
+        <span class="text-white">详情</span>
+    </template>
+</van-nav-bar>
+<div class="base-content">
+    <div class="header">
+        <div class="left">
+            <div class="salary-box">
+                <van-image
+                        width="15px"
+                        src="__MIMAGES__/icon_salary_white.png"
+                ></van-image>
+                <span class="text">工资:</span>
+                <span class="salary">{{info.salary}}</span>
+            </div>
+            <div class="company-name">{{info.company_name}}</div>
+        </div>
+        <div class="phone-box" @click="onPhone">
+            <van-image
+                    width="30px"
+                    src="__MIMAGES__/icon_phone_white.png"
+            ></van-image>
+            <span class="text">拔号</span>
+        </div>
+    </div>
+    <div class="title">{{info.title}}</div>
+    <div class="tags" v-if="info.tags.length > 0">
+        <van-tag type="primary" size="large" v-for="tag in info.tags">{{tag}}</van-tag>
+    </div>
+    <div class="introduce">
+        <div class="introduce-item">
+            <van-image
+                    width="15px"
+                    src="__MIMAGES__/icon_num.png"
+            ></van-image>
+            <span>招聘人数:{{info.num}}</span>
+            <span class="split">|</span>
+            <van-image
+                    width="15px"
+                    src="__MIMAGES__/icon_age.png"
+            ></van-image>
+            <span>年龄:{{info.agegroup}}</span>
+        </div>
+        <div class="introduce-item">
+            <van-image
+                    width="15px"
+                    src="__MIMAGES__/icon_address.png"
+            ></van-image>
+            <span>{{info.province}}{{info.city}}{{info.district}}{{info.address}}</span>
+        </div>
+    </div>
+</div>
+
+<div class="describe" v-if="info.requirement">
+    <div class="header">
+        岗位要求
+    </div>
+    <div class="content">
+        <pre>{{info.requirement}}</pre>
+    </div>
+</div>
+
+<div class="describe" v-if="info.comdetails">
+    <div class="header">
+        企业简介
+    </div>
+    <div class="content">
+        <pre>{{info.comdetails}}</pre>
+    </div>
+</div>
+
+<div class="describe" v-if="info.picall.length > 0">
+    <div class="header">
+        相册
+    </div>
+    <div class="content">
+        <van-grid :border="false">
+            <van-grid-item v-for="(image,index) in info.picall">
+                <van-image
+                        :src="image"
+                        @click="showImage(index)"
+                ></van-image>
+            </van-grid-item>
+        </van-grid>
+    </div>
+</div>
+
+<div class="describe" v-if="info.remark">
+    <div class="header">
+        补充说明
+    </div>
+    <div class="content">
+        <pre>{{info.remark}}</pre>
+    </div>
+</div>
+
+<van-floating-bubble @click="onReport">报备</van-floating-bubble>
+{/block}
+{block name="script"}
+<script>
+    function v_setup() {
+        let base = {};
+
+        base.active = Vue.ref(0);
+
+        base.info = Vue.reactive({$info});
+        base.onPhone = () => {
+            location.href = 'tel:' + base.info.telephone;
+        };
+        base.showImage = (index) => {
+            vant.showImagePreview({
+                images: base.info.picall,
+                startPosition: index,
+                loop:false,
+            });
+        };
+
+        base.onReport = () => {
+            location.href = "{:url('recruit/report')}?id=" + base.info.id;
+        };
+
+        base.onBack = () => {
+            location.href = "{:url('recruit/index')}";
+        };
+
+        return base;
+    }
+</script>
+{/block}

+ 66 - 0
app/mobile/view/recruit/index.html

@@ -0,0 +1,66 @@
+{extend name="public/base"/}
+{block name="css"}
+<style>
+    .footer-block{width:100%;height:60px;}
+    .footer{position:fixed;width:100%;left:0;bottom:0;box-sizing:border-box;padding:5px 20px;background:white;}
+</style>
+{/block}
+{block name="body"}
+<van-nav-bar
+        class="nav-theme"
+        :fixed="true"
+        :placeholder="true"
+        left-text="返回"
+        left-arrow
+        @click-left="onBack"
+>
+    <template #title>
+        <span class="text-white">招聘信息</span>
+    </template>
+</van-nav-bar>
+<van-search
+        v-model="form.keyword"
+        placeholder="请输入标题或公司名"
+        @search="onSearch"
+        @cancel="onCancel"
+        show-action
+>
+    <template #action>
+        <div @click="onCancel">重置</div>
+    </template>
+</van-search>
+
+{include file="public/list_load" list="<recruit-list @detail='toDetail' :list='list'></recruit-list>" /}
+{/block}
+{block name="script"}
+<script>
+    function v_setup() {
+        let base = list_load('recruit/listRecruit',{keyword:''});
+
+        //搜索
+        base.onSearch = () => {
+            base.onRefresh();
+        };
+        base.onCancel = () => {
+            base.form.keyword = "";
+            base.onRefresh();
+        };
+
+        //列表
+        base.toDetail = (id) => {
+            location.href = "{:url('/mobile/recruit/detail')}?id=" + id;
+        };
+
+
+        //头部
+        base.onBack = () => {
+            location.href = "{:url('/mobile/my/index')}";
+        };
+
+        return base;
+    }
+</script>
+{/block}
+{block name="vue"}
+    <script src="__COMPONENTS__/recruitList.js"></script>
+{/block}

+ 179 - 0
app/mobile/view/recruit/report.html

@@ -0,0 +1,179 @@
+{extend name="public/base"/}
+{block name="css"}
+<style>
+    .recruit {background:white;padding:10px 20px;}
+    .recruit .title {font-size:18px;padding:10px 0;font-weight:bold;color:#000;}
+    .recruit .company-name {font-size:14px;color:#aaa;}
+</style>
+{/block}
+{block name="body"}
+<van-nav-bar
+        class="nav-theme"
+        :fixed="true"
+        :placeholder="true"
+        left-text="返回"
+        left-arrow
+        @click-left="onBack"
+>
+    <template #title>
+        <span class="text-white">报备</span>
+    </template>
+</van-nav-bar>
+<div class="recruit">
+    <div class="title">{{info.title}}</div>
+    <div class="company-name">{{info.company_name}}</div>
+</div>
+
+<van-tabs v-model:active="active" style="margin-top:10px;">
+    <van-tab title="报备信息">
+        <div class="report">
+            <van-form @submit="onSubmit">
+                <van-cell-group>
+                    <van-field
+                            v-model="form.realname"
+                            required
+                            label="姓名"
+                            placeholder="请填写姓名"
+                            :rules="[{ required: true, message: '请填写姓名' }]"
+                    ></van-field>
+                    <van-field
+                            v-model="form.mobile"
+                            required
+                            label="电话"
+                            placeholder="请填写电话"
+                            :rules="[
+                                { required: true, message: '请填写电话' },
+                                { validator, message: '请输入正确的手机号'}
+                            ]"
+                    ></van-field>
+                    <van-field
+                            v-model="form.idcard"
+                            required
+                            label="身份证"
+                            placeholder="请填写身份证号"
+                            :rules="[{ required: true, message: '请填写身份证号' }]"
+                    ></van-field>
+                    <van-field
+                            v-model="form.arrivetime"
+                            required
+                            is-link
+                            readonly
+                            label="出发日期"
+                            placeholder="出发日期"
+                            @click="showArrivetime = true"
+                    ></van-field>
+                    <van-popup v-model:show="showArrivetime" round position="bottom">
+                        <van-date-picker
+                                title="选择日期"
+                                :min-date="minDate"
+                                @confirm="selectArrivetime"
+                                @cancel="showArrivetime = false"
+                        ></van-date-picker>
+                    </van-popup>
+                    <van-field
+                            v-model="form.remark"
+                            rows="2"
+                            autosize
+                            label="备注"
+                            type="textarea"
+                            maxlength="1000"
+                            placeholder="请输入备注"
+                            show-word-limit
+                    ></van-field>
+                </van-cell-group>
+                <div style="margin: 16px;">
+                    <van-button round block type="primary" native-type="submit">
+                        提交
+                    </van-button>
+                </div>
+            </van-form>
+        </div>
+    </van-tab>
+    <van-tab title="我的用户库">
+        <van-search
+                v-model="form.searchKey"
+                placeholder="请输入姓名或手机号"
+                @search="onSearch"
+                @cancel="onCancel"
+                show-action
+        >
+            <template #action>
+                <div @click="onCancel">重置</div>
+            </template>
+        </van-search>
+        {include file="public/list_load" list="<resume-list @deal='onDeal' :is_select='true' :list='list'></resume-list>" /}
+    </van-tab>
+</van-tabs>
+{/block}
+{block name="script"}
+<script>
+    function v_setup() {
+        let base = list_load('resume/listResume',{searchKey:''});
+        base.info = {$info};
+
+        //标签页
+        base.active = Vue.ref(0);
+
+        //表单
+        base.form = Vue.reactive({
+            recruit_id: base.info.id,
+            realname: '',
+            mobile: '',
+            idcard: '',
+            arrivetime: '',
+            remark: '',
+        });
+
+        //出发日期
+        base.showArrivetime = Vue.ref(false);
+        base.minDate = new Date();
+        base.selectArrivetime = (value) => {
+            base.form.arrivetime = value.selectedValues.join('-');
+            base.showArrivetime.value = false;
+        };
+
+        //搜索
+        base.onSearch = () => {
+            base.onRefresh();
+        };
+        base.onCancel = () => {
+            base.form.keyword = "";
+            base.onRefresh();
+        };
+
+        //表单提交
+        base.onSubmit = () => {
+            postJson("{:url('recruit/reportPost')}", base.form).then(({data}) => {
+                vant.showDialog({
+                    title: '提示',
+                    message: '提交成功',
+                }).then(() => {
+                    history.back();
+                });
+            });
+        };
+
+        //选择简历库
+        base.onDeal = (info) => {
+            base.form.realname = info.name;
+            base.form.mobile = info.mobile;
+            base.form.idcard = info.idcard;
+            base.active.value = 0;
+        };
+
+        //手机号验证
+        base.validator = (val) => {
+            return /^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$/.test(val);
+        };
+
+        base.onBack = () => {
+            history.back();
+        };
+
+        return base;
+    }
+</script>
+{/block}
+{block name="vue"}
+<script src="__COMPONENTS__/resumeList.js"></script>
+{/block}

+ 15 - 2
public/static/mobile/css/style.css

@@ -37,7 +37,7 @@ html {
 .income-list .income-item .left .time {color: #aaaaaa;font-size: 12px;}
 .income-list .income-item .left .comment {color: #aaaaaa;font-size: 12px;}
 .income-list .income-item .right {color: #e54d42;}
-.income-list .income-item .right .text {color: #0081ff;}
+.income-list .income-item .right .text {color: #0081ff;text-align:right;}
 .income-list .income-item .right .money {color: #e54d42;}
 
 .resume-list .resume-item{background:white;margin-top:10px;padding:10px 20px;}
@@ -49,4 +49,17 @@ html {
 .resume-list .resume-item .content .remark {padding-bottom:5px;color:var(--orange);}
 .resume-list .resume-item .content .time {color:var(--gray);font-size:14px;}
 .resume-list .resume-item .tool {display:flex;align-items:center;justify-content:flex-end;}
-.resume-list .resume-item .tool .van-tag{margin-left:10px;}
+.resume-list .resume-item .tool .van-tag{margin-left:10px;}
+
+.recruit-list .recruit-item {background:white;margin-top:10px;padding:10px 20px;}
+.recruit-list .recruit-item .title{display:flex;padding-bottom:10px;border-bottom:1px solid #eee;}
+.recruit-list .recruit-item .title .title-name {width:calc(100% - 110px);}
+.recruit-list .recruit-item .title .salary {width:110px;text-align:center;color:var(--red);display: flex;align-items: center;justify-content: flex-end;}
+.recruit-list .recruit-item .title .salary span {margin-left:5px;}
+.recruit-list .recruit-item .content {display:flex;align-items:center;justify-content:center;padding-top:10px;}
+.recruit-list .recruit-item .content .content-item {text-align:left;flex:1;display:flex;align-items:center;justify-content:flex-start;height:30px;}
+.recruit-list .recruit-item .tags {padding:5px 0;}
+.recruit-list .recruit-item .tags .van-tag{margin-right:5px;}
+.recruit-list .recruit-item .bottom {border-top:1px solid #eee;margin-top:10px;display:flex;padding-top:10px;font-size:14px;color:#666;}
+.recruit-list .recruit-item .bottom .company-name{width:calc(100% - 80px);}
+.recruit-list .recruit-item .bottom .volume{width:80px;display:flex;align-items:center;justify-content:flex-end;}

BIN
public/static/mobile/images/detail_header.jpg


BIN
public/static/mobile/images/icon_address.png


BIN
public/static/mobile/images/icon_age.png


BIN
public/static/mobile/images/icon_num.png


BIN
public/static/mobile/images/icon_phone_white.png


BIN
public/static/mobile/images/icon_qrcode.png


BIN
public/static/mobile/images/icon_salary.png


BIN
public/static/mobile/images/icon_salary_white.png


BIN
public/static/mobile/images/icon_volume.png


+ 63 - 0
public/static/mobile/js/components/recruitList.js

@@ -0,0 +1,63 @@
+app.component('recruit-list', {
+    template: `
+    <div class="recruit-list">
+        <div class="recruit-item" v-for="item in list" @click="toDetail(item.id)">
+            <div class="title">
+                <div class="title-name">{{item.title}}</div>
+                <div class="salary">
+                    <van-image
+                            width="20px"
+                            src="/static/mobile/images/icon_salary.png"
+                    ></van-image>
+                    <span>{{item.salary}}</span>
+                </div>
+            </div>
+            <div class="content">
+                <div class="content-item">
+                    <van-image
+                            width="15px"
+                            src="/static/mobile/images/icon_age.png"
+                    ></van-image>
+                    <span>{{item.agegroup}}</span>
+                </div>
+                <div class="content-item">
+                    <van-image
+                            width="15px"
+                            src="/static/mobile/images/icon_num.png"
+                    ></van-image>
+                    <span>{{item.num}}</span>
+                </div>
+            </div>
+            <div class="tags">
+                <van-tag type="primary" size="large" v-for="tag in item.tags">{{tag}}</van-tag>
+            </div>
+            <div class="bottom">
+                <div class="company-name">
+                    {{item.company_name}}
+                </div>
+                <div class="volume">
+                    <van-image
+                            width="20px"
+                            src="/static/mobile/images/icon_volume.png"
+                    ></van-image>
+                    <span>{{item.volume}}</span>
+                </div>
+            </div>
+        </div>
+    </div>
+    `,
+    data() {
+        return {}
+    },
+    props: {
+        list: {
+            type: Array,
+            default: [],
+        },
+    },
+    methods: {
+        toDetail(id) {
+            this.$emit('detail',id);
+        },
+    },
+});

+ 11 - 1
public/static/mobile/js/components/resumeList.js

@@ -10,10 +10,13 @@ app.component('resume-list', {
                 <div class="remark">{{item.last_msg}}</div>
                 <div class="time">{{item.last_msg_time}}</div>
             </div>
-            <div class="tool">
+            <div class="tool" v-if="!is_select">
                 <van-tag type="primary" plain size="large" @click="onFollow(item.id)">跟进</van-tag>
                 <van-tag type="success" plain size="large" @click="onEdit(item.id)">编辑</van-tag>
             </div>
+            <div class="tool" v-if="is_select">
+                <van-tag type="primary" plain size="large" @click="onDeal(item)">选择</van-tag>
+            </div>
         </div>
     </div>
     `,
@@ -25,6 +28,10 @@ app.component('resume-list', {
             type: Array,
             default: [],
         },
+        is_select: {
+            type: Boolean,
+            default: false,
+        },
     },
     methods: {
         onFollow(id) {
@@ -33,5 +40,8 @@ app.component('resume-list', {
         onEdit(id) {
             this.$emit('edit',id);
         },
+        onDeal(info) {
+            this.$emit('deal',info);
+        },
     },
 });