Browse Source

新增页面

LuChongMei 1 year ago
parent
commit
6726ebba5a
48 changed files with 3243 additions and 67 deletions
  1. 0 1
      jp-console/jeeplus-modules/gw/src/main/java/com/jeeplus/circulation2/controller/GwCirculationCard2Controller.java
  2. 18 1
      jp-console/jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/controller/UserController.java
  3. 1 0
      jp-console/jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/mapper/UserMapper.java
  4. 8 0
      jp-console/jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/mapper/xml/UserMapper.xml
  5. 5 0
      jp-console/jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/service/UserService.java
  6. 60 0
      jp-mobile/api/circulation/gwCirculationCard2.js
  7. 8 1
      jp-mobile/api/sys/userService.js
  8. 7 1
      jp-mobile/common/util.js
  9. 83 0
      jp-mobile/components/am-sign-input/README.md
  10. 781 0
      jp-mobile/components/am-sign-input/am-sign-input.vue
  11. 143 0
      jp-mobile/components/am-sign-input/pickerColor.vue
  12. 124 0
      jp-mobile/components/am-sign-input/u-mask/u-mask.vue
  13. 2 2
      jp-mobile/components/jp-datetime-picker/jp-datetime-picker.vue
  14. 2 2
      jp-mobile/components/jp-picker/jp-picker.vue
  15. 223 0
      jp-mobile/components/office-user-select/office-user-select.vue
  16. 1 1
      jp-mobile/config.js
  17. 19 19
      jp-mobile/package.json
  18. 31 1
      jp-mobile/pages.json
  19. 196 0
      jp-mobile/pages/fileTransmit/addFileTransmit.vue
  20. 142 0
      jp-mobile/pages/fileTransmit/examineFile.vue
  21. 249 0
      jp-mobile/pages/fileTransmit/fileCard.vue
  22. 32 0
      jp-mobile/pages/fileTransmit/fileInfo.vue
  23. 113 0
      jp-mobile/pages/fileTransmit/fileTransmitList.vue
  24. 16 0
      jp-mobile/pages/fileTransmit/statistics.vue
  25. 6 6
      jp-mobile/pages/index/index.vue
  26. 47 28
      jp-mobile/pages/workbench/workbench.vue
  27. 1 0
      jp-mobile/static/css/main.css
  28. BIN
      jp-mobile/static/index/icon1.png
  29. BIN
      jp-mobile/static/index/icon2.png
  30. BIN
      jp-mobile/static/index/icon3.png
  31. BIN
      jp-mobile/static/index/icon4.png
  32. BIN
      jp-mobile/static/index/icon5.png
  33. BIN
      jp-mobile/static/index/icon6.png
  34. BIN
      jp-mobile/static/other/color_black.png
  35. BIN
      jp-mobile/static/other/color_black_selected.png
  36. BIN
      jp-mobile/static/other/color_red.png
  37. BIN
      jp-mobile/static/other/color_red_selected.png
  38. BIN
      jp-mobile/static/other/signs.png
  39. 37 0
      jp-mobile/uni_modules/uni-data-select/changelog.md
  40. 527 0
      jp-mobile/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue
  41. 85 0
      jp-mobile/uni_modules/uni-data-select/package.json
  42. 8 0
      jp-mobile/uni_modules/uni-data-select/readme.md
  43. 2 0
      jp-mobile/uni_modules/uni-section/changelog.md
  44. 167 0
      jp-mobile/uni_modules/uni-section/components/uni-section/uni-section.vue
  45. 87 0
      jp-mobile/uni_modules/uni-section/package.json
  46. 8 0
      jp-mobile/uni_modules/uni-section/readme.md
  47. 3 3
      jp-ui/src/App.vue
  48. 1 1
      jp-ui/src/main.js

+ 0 - 1
jp-console/jeeplus-modules/gw/src/main/java/com/jeeplus/circulation2/controller/GwCirculationCard2Controller.java

@@ -173,7 +173,6 @@ public class GwCirculationCard2Controller {
 	 */
 	@ApiLog("保存公文流转")
 	@ApiOperation(value = "保存公文流转")
-	@PreAuthorize("hasAnyAuthority('circulation2:gwCirculationCard2:add','circulation2:gwCirculationCard2:edit')")
 	@PostMapping("save")
 	public  ResponseEntity <String> save(@Valid @RequestBody GwCirculationCard2DTO gwCirculationCard2DTO) {
 		//新增或编辑表单保存

+ 18 - 1
jp-console/jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/controller/UserController.java

@@ -89,7 +89,24 @@ public class UserController {
         return ResponseEntity.ok ( result );
     }
 
-
+    /**
+     * 获取科室用户列表
+     *
+     * @param userDTO
+     * @return
+     */
+    @ApiLog("获取科室用户列表")
+    @ApiOperation(value = "获取科室用户列表")
+    @PreAuthorize("hasAuthority('sys:user:list')")
+    @GetMapping("officeList")
+    public ResponseEntity officeList(UserDTO userDTO) throws Exception {
+        QueryWrapper <UserDTO> queryWrapper = QueryWrapperGenerator.buildQueryCondition ( userDTO, UserDTO.class );
+        if ( userDTO.getTenantDTO ( ) != null && StrUtil.isNotBlank ( userDTO.getTenantDTO ( ).getId ( ) ) ) {
+            queryWrapper.eq ( "a.tenant_id", userDTO.getTenantDTO ( ).getId ( ) );
+        }
+        List <UserDTO> result = userService.findOfficeList ( queryWrapper );
+        return ResponseEntity.ok ( result );
+    }
     /**
      * 保存用户
      *

+ 1 - 0
jp-console/jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/mapper/UserMapper.java

@@ -104,4 +104,5 @@ public interface UserMapper extends BaseMapper <User> {
      */
     void insertUserPost(@Param("userId") String userId, @Param("postId") String postId);
 
+    List<UserDTO> findOfficeList(@Param(Constants.WRAPPER) QueryWrapper<UserDTO> queryWrapper);
 }

+ 8 - 0
jp-console/jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/mapper/xml/UserMapper.xml

@@ -160,4 +160,12 @@
         INSERT INTO sys_user_post(user_id, post_id)
         VALUES (#{userId}, #{postId})
     </insert>
+<!--    获取科室用户列表-->
+    <select id="findOfficeList" resultMap="userResult">
+        SELECT
+        <include refid="userColumns"/>
+        FROM sys_user a
+        <include refid="userJoins"/>
+        ${ew.customSqlSegment}
+    </select>
 </mapper>

+ 5 - 0
jp-console/jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/service/UserService.java

@@ -219,4 +219,9 @@ public class UserService extends ServiceImpl <UserMapper, User> {
         user.setLoginDate(new Date ());
         super.updateById (user);
     }
+
+    public List<UserDTO> findOfficeList(QueryWrapper<UserDTO> queryWrapper) {
+        queryWrapper.like("o.parent_ids","1771063850830143489");
+        return baseMapper.findOfficeList(queryWrapper);
+    }
 }

+ 60 - 0
jp-mobile/api/circulation/gwCirculationCard2.js

@@ -0,0 +1,60 @@
+import request from "../../common/request";
+
+export default {
+	save: function (inputForm) {
+		return request({
+			url: "/circulation2/gwCirculationCard2/save",
+			method: "post",
+			data: inputForm,
+		});
+	},
+
+	delete: function (ids) {
+		return request({
+			url: "/circulation2/gwCirculationCard2/delete",
+			method: "delete",
+			params: { ids: ids },
+		});
+	},
+
+	queryById: function (id) {
+		return request({
+			url: "/circulation2/gwCirculationCard2/queryById",
+			method: "get",
+			params: { id: id },
+		});
+	},
+
+	list: function (params) {
+		return request({
+			url: "/circulation2/gwCirculationCard2/list2",
+			method: "get",
+			params: params,
+		});
+	},
+
+	exportTemplate: function () {
+		return request({
+			url: "/circulation2/gwCirculationCard2/import/template",
+			method: "get",
+			responseType: "blob",
+		});
+	},
+
+	exportExcel: function (params) {
+		return request({
+			url: "/circulation2/gwCirculationCard2/export",
+			method: "get",
+			params: params,
+			responseType: "blob",
+		});
+	},
+
+	importExcel: function (data) {
+		return request({
+			url: "/circulation2/gwCirculationCard2/import",
+			method: "post",
+			data: data,
+		});
+	},
+};

+ 8 - 1
jp-mobile/api/sys/userService.js

@@ -55,5 +55,12 @@ export default {
 			method: "get",
 			params: params,
 		});
-	}
+	},
+	officeList: function (params) {
+		return request({
+			url: "/sys/user/officeList",
+			method: "get",
+			params: params,
+		});
+	},
 }

+ 7 - 1
jp-mobile/common/util.js

@@ -79,10 +79,16 @@ function toLine (name) {
     return name
   }
 }
+// 使用正则表达式判断文件名或URL是否为图片格式
+function isImageFormat(filename) {
+  const imageFormats = /\.(jpeg|jpg|gif|png|bmp|svg)$/i;
+  return imageFormats.test(filename);
+}
 
 module.exports = {
 	Base64:Base64,
 	recover: recover,
 	recoverNotNull: recoverNotNull,
-	toLine: toLine
+	toLine: toLine,
+	isImageFormat:isImageFormat
 }

+ 83 - 0
jp-mobile/components/am-sign-input/README.md

@@ -0,0 +1,83 @@
+### 使用方法
+* 注意
++ 同一个页面不同的输入框需要设置不同的canvasId和canvasIds,否则在同一个页面会出现冲突
+```
+<template>
+	<view class="content">
+		<signInput ref="sign" canvasId="twoDrowCanvas" canvasIds="twoRotateCanvas" :header="header" :action="action"
+			@signToUrl="signToUrl">
+		</signInput>
+	</view>
+</template>
+```
+```
+<script>
+	import signInput from "@/components/am-sign-input/am-sign-input.vue"
+	export default {
+		components: {
+			signInput
+		},
+		data() {
+			return {
+				action: "", //上传服务器的地址
+				header: {}, //图片上传携带头部信息
+			}
+		},
+		methods: {
+			/**
+			 * @param {Object} e
+			 * 签名完成回调
+			 */
+			signToUrl(e) {
+				if (e.error_code && e.error_code === '201') {
+					uni.showToast({
+						title: e.msg,
+						icon: 'none'
+					})
+					return
+				}
+			},
+		}
+	}
+</script>
+```
+```
+<style lang="scss">
+	.content {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+	}
+</style>
+```
+
+#### 实际效果演示H5
+- 打开演示后,按F12调整到手机调试模式查看效果
+[实际效果演示](https://static-mp-2766f90e-0e50-4c71-87fb-0ab51aedcf85.next.bspapp.com/signInput/#/)
+
+### 参数说明Props
+
+参数|类型|说明|必传
+---|---|---|---
+action|String|生成图片后上传的接口地址|true
+canvasId|String|canvasId|true
+canvasIds|String|canvasIds与上一个id不可重复|true
+header|Object|文件上传携带的头部属性|true
+outSignWidth|Number|输出图片文件大小-宽度|false
+outSignHeight|Number|输出图片文件大小-高度|false
+minSpeed|Number|画笔最小速度|false
+minWidth|Number|线条最小粗度|false
+maxWidth|Number|线条最大粗度|false
+openSmooth|Boolean|开启平滑线条(笔锋)|false
+maxHistoryLength|Number|历史最大长度(用于撤销的步数)|false
+maxWidthDiffRate|Number|最大差异率|false
+undoScan|Number|撤销重新渲染偏移缩放校准|false
+bgColor|String|背景色如#ffffff 不传则为透明|false
+
+### 相关同源插件
+- 以页面形式展现
+- [电子签名组件](https://ext.dcloud.net.cn/plugin?id=5768)
+
+### 相关致谢
+- 插件参考 [大佬的npm库](https://github.com/linjc/smooth-signature)

+ 781 - 0
jp-mobile/components/am-sign-input/am-sign-input.vue

@@ -0,0 +1,781 @@
+<template>
+	<view class="sign">
+		<view class="imgBox">
+			<view class="nom_img" v-if="!showImg" @click="signModShow=true">
+				<image v-if="!showImg" src="/static/other/signs.png" style="width: 34px;height: 34px;">
+				</image>
+			</view>
+			<view class="across_img" v-if="showImg">
+				<view v-if="showImg" class="delete_icon" @click.stop="deleteImg">
+					x
+				</view>
+				<image v-if="showImg" :src="showImg" style="width: 140px;height: 80px;" @click="previewImg(showImg)">
+				</image>
+			</view>
+		</view>
+
+		<umask :show="signModShow" @click="signModShow=false" :duration="0">
+			<view class="warp">
+				<view class="signBox" @tap.stop>
+					<view class="wrapper">
+						<view class="handBtn">
+							<!-- #ifdef MP-WEIXIN -->
+							<image @click="selectColorEvent('black','#1A1A1A')"
+								:src="selectColor === 'black' ? '/static/other/color_black_selected.png' : '/static/other/color_black.png'"
+								class="black-select"></image>
+							<image @click="selectColorEvent('red','#ca262a')"
+								:src="selectColor === 'red' ? '/static/other/color_red_selected.png' : '/static/other/color_red.png'"
+								class="red-select"></image>
+							<!-- #endif -->
+							<!-- #ifndef MP-WEIXIN -->
+							<view class="color_pic" :style="{background:lineColor}" @click="showPickerColor=true">
+							</view>
+							<!-- #endif -->
+							<button @click="clear" class="delBtn">清空</button>
+							<button @click="saveCanvasAsImg" class="saveBtn">保存</button>
+							<button @click="previewCanvasImg" class="previewBtn">预览</button>
+							<button @click="subCanvas" class="subBtn">完成</button>
+							<button @click="undo" class="undoBtn">撤销</button>
+							<span class="emptyInfo" style="color: red;" v-if="emptyShow">你还没有绘制任何东西哦</span>
+						</view>
+						<view class="handCenter" :style="{left:canvasLeft+'px'}">
+							<canvas :disable-scroll="true" @touchstart="uploadScaleStart" @touchmove="uploadScaleMove"
+								@touchend="uploadScaleEnd" :style="{width:'100%',height:'calc(85vh - 8rpx)'}"
+								:canvas-id="canvasId"></canvas>
+						</view>
+
+						<view class="handCenters">
+							<canvas :canvas-id="canvasIds"
+								:style="{width:outSignWidth+'px',height:outSignHeight+'px'}"></canvas>
+						</view>
+						<view class="handRight">
+							<view class="handTitle">请签名
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</umask>
+		<pickerColor :isShow="showPickerColor" :bottom="0" @callback='getPickerColor' />
+	</view>
+</template>
+
+<script>
+	import umask from "./u-mask/u-mask.vue"
+	import pickerColor from "./pickerColor.vue"
+	export default {
+		components: {
+			umask,
+			pickerColor
+		},
+		data() {
+			return {
+				canvasLeft: 10000,
+				emptyShow: false,
+				signModShow: false,
+				showImg: "",
+				showPickerColor: false,
+				ctx: '',
+				ctxs: '',
+				canvasWidth: 0,
+				canvasHeight: 0,
+				selectColor: 'black',
+				lineColor: '#1A1A1A',
+				points: [],
+				historyList: [],
+				canAddHistory: true,
+				getImagePath: () => {
+					let that = this
+					return new Promise((resolve) => {
+						uni.canvasToTempFilePath({
+							canvasId: that.canvasId,
+							fileType: 'png',
+							quality: 1, //图片质量
+							success: res => resolve(res.tempFilePath)
+						}, this)
+					})
+				},
+				requestAnimationFrame: void 0,
+			};
+		},
+		watch: {
+			signModShow(newValue, oldValue) {
+				newValue ? this.canvasLeft = 74 : this.canvasLeft = 10000
+			}
+		},
+		props: { //可用于修改的参数放在props里   也可单独放在外面做成组件调用  传值
+			action: {
+				type: String,
+				default: ''
+			},
+			canvasId: {
+				type: String,
+				default: 'canvasDr'
+			},
+			canvasIds: {
+				type: String,
+				default: 'canvasRo'
+			},
+			header: {
+				type: Object,
+				default: {}
+			},
+			outSignWidth: {
+				type: Number,
+				default: 54
+			},
+			outSignHeight: {
+				type: Number,
+				default: 24
+			},
+			minSpeed: { //画笔最小速度
+				type: Number,
+				default: 1.5
+			},
+			minWidth: { //线条最小粗度
+				type: Number,
+				default: 3,
+			},
+			maxWidth: { //线条最大粗度
+				type: Number,
+				default: 10
+			},
+			openSmooth: { //开启平滑线条(笔锋)
+				type: Boolean,
+				default: true
+			},
+			maxHistoryLength: { //历史最大长度
+				type: Number,
+				default: 20
+			},
+			maxWidthDiffRate: { //最大差异率
+				type: Number,
+				default: 20
+			},
+			undoScan: { //撤销重新渲染偏移缩放校准
+				type: Number,
+				default: 0.83
+			},
+			bgColor: { //背景色
+				type: String,
+				default: ''
+			},
+		},
+		mounted() {
+			if (!this.ctx) {
+				this.ctx = uni.createCanvasContext(this.canvasId, this);
+			}
+			if (!this.ctxs) {
+				this.ctxs = uni.createCanvasContext(this.canvasIds, this);
+			}
+			let that = this
+			this.$nextTick(() => {
+				uni.createSelectorQuery().in(this).select('.handCenter').boundingClientRect(rect => {
+						that.canvasWidth = rect.width;
+						that.canvasHeight = rect.height;
+						that.drawBgColor()
+					})
+					.exec();
+			})
+		},
+		methods: {
+			getPickerColor(color) {
+				this.showPickerColor = false;
+				if (color) {
+					this.lineColor = color;
+				}
+			},
+			// 笔迹开始
+			uploadScaleStart(e) {
+				this.canAddHistory = true
+				this.ctx.setStrokeStyle(this.lineColor)
+				this.ctx.setLineCap("round") //'butt'、'round'、'square'
+			},
+			// 笔迹移动
+			uploadScaleMove(e) {
+				let temX = e.changedTouches[0].x
+				let temY = e.changedTouches[0].y
+				this.initPoint(temX, temY)
+				this.onDraw()
+			},
+			/**
+			 * 触摸结束
+			 */
+			uploadScaleEnd() {
+				this.canAddHistory = true;
+				this.points = [];
+			},
+			/**
+			 * 记录点属性
+			 */
+			initPoint(x, y) {
+				var point = {
+					x: x,
+					y: y,
+					t: Date.now()
+				};
+				var prePoint = this.points.slice(-1)[0];
+				if (prePoint && (prePoint.t === point.t || prePoint.x === x && prePoint.y === y)) {
+					return;
+				}
+				if (prePoint && this.openSmooth) {
+					var prePoint2 = this.points.slice(-2, -1)[0];
+					point.distance = Math.sqrt(Math.pow(point.x - prePoint.x, 2) + Math.pow(point.y - prePoint.y, 2));
+					point.speed = point.distance / (point.t - prePoint.t || 0.1);
+					point.lineWidth = this.getLineWidth(point.speed);
+					if (prePoint2 && prePoint2.lineWidth && prePoint.lineWidth) {
+						var rate = (point.lineWidth - prePoint.lineWidth) / prePoint.lineWidth;
+						var maxRate = this.maxWidthDiffRate / 100;
+						maxRate = maxRate > 1 ? 1 : maxRate < 0.01 ? 0.01 : maxRate;
+						if (Math.abs(rate) > maxRate) {
+							var per = rate > 0 ? maxRate : -maxRate;
+							point.lineWidth = prePoint.lineWidth * (1 + per);
+						}
+					}
+				}
+				this.points.push(point);
+				this.points = this.points.slice(-3);
+			},
+			/**
+			 * @param {Object} 
+			 * 线宽
+			 */
+			getLineWidth(speed) {
+				var minSpeed = this.minSpeed > 10 ? 10 : this.minSpeed < 1 ? 1 : this.minSpeed; //1.5
+				var addWidth = (this.maxWidth - this.minWidth) * speed / minSpeed;
+				var lineWidth = Math.max(this.maxWidth - addWidth, this.minWidth);
+				return Math.min(lineWidth, this.maxWidth);
+			},
+			/**
+			 * 绘画逻辑
+			 */
+			onDraw() {
+				if (this.points.length < 2) return;
+				this.addHistory();
+				var point = this.points.slice(-1)[0];
+				var prePoint = this.points.slice(-2, -1)[0];
+				let that = this
+				var onDraw = function onDraw() {
+					if (that.openSmooth) {
+						that.drawSmoothLine(prePoint, point);
+					} else {
+						that.drawNoSmoothLine(prePoint, point);
+					}
+				};
+				if (typeof this.requestAnimationFrame === 'function') {
+					this.requestAnimationFrame(function() {
+						return onDraw();
+					});
+				} else {
+					onDraw();
+				}
+			},
+			//添加历史图片地址
+			addHistory() {
+				if (!this.maxHistoryLength || !this.canAddHistory) return;
+				this.canAddHistory = false;
+				if (!this.getImagePath) {
+					this.historyList.length++;
+					return;
+				}
+				//历史地址 (暂时无用)
+				let that = this
+				that.getImagePath().then(function(url) {
+					if (url) {
+						that.historyList.push(url)
+						that.historyList = that.historyList.slice(-that.maxHistoryLength);
+					}
+				});
+			},
+			//画平滑线
+			drawSmoothLine(prePoint, point) {
+				var dis_x = point.x - prePoint.x;
+				var dis_y = point.y - prePoint.y;
+
+				if (Math.abs(dis_x) + Math.abs(dis_y) <= 2) {
+					point.lastX1 = point.lastX2 = prePoint.x + dis_x * 0.5;
+					point.lastY1 = point.lastY2 = prePoint.y + dis_y * 0.5;
+				} else {
+					point.lastX1 = prePoint.x + dis_x * 0.3;
+					point.lastY1 = prePoint.y + dis_y * 0.3;
+					point.lastX2 = prePoint.x + dis_x * 0.7;
+					point.lastY2 = prePoint.y + dis_y * 0.7;
+				}
+				point.perLineWidth = (prePoint.lineWidth + point.lineWidth) / 2;
+				if (typeof prePoint.lastX1 === 'number') {
+					this.drawCurveLine(prePoint.lastX2, prePoint.lastY2, prePoint.x, prePoint.y, point.lastX1, point
+						.lastY1, point.perLineWidth);
+					if (prePoint.isFirstPoint) return;
+					if (prePoint.lastX1 === prePoint.lastX2 && prePoint.lastY1 === prePoint.lastY2) return;
+					var data = this.getRadianData(prePoint.lastX1, prePoint.lastY1, prePoint.lastX2, prePoint.lastY2);
+					var points1 = this.getRadianPoints(data, prePoint.lastX1, prePoint.lastY1, prePoint.perLineWidth / 2);
+					var points2 = this.getRadianPoints(data, prePoint.lastX2, prePoint.lastY2, point.perLineWidth / 2);
+					this.drawTrapezoid(points1[0], points2[0], points2[1], points1[1]);
+				} else {
+					point.isFirstPoint = true;
+				}
+			},
+			//画不平滑线
+			drawNoSmoothLine(prePoint, point) {
+				point.lastX = prePoint.x + (point.x - prePoint.x) * 0.5;
+				point.lastY = prePoint.y + (point.y - prePoint.y) * 0.5;
+				if (typeof prePoint.lastX === 'number') {
+					this.drawCurveLine(prePoint.lastX, prePoint.lastY, prePoint.x, prePoint.y, point.lastX, point.lastY,
+						this.maxWidth);
+				}
+			},
+			//画线
+			drawCurveLine(x1, y1, x2, y2, x3, y3, lineWidth) {
+				lineWidth = Number(lineWidth.toFixed(1));
+				this.ctx.setLineWidth && this.ctx.setLineWidth(lineWidth);
+				this.ctx.lineWidth = lineWidth;
+				this.ctx.beginPath();
+				this.ctx.moveTo(Number(x1.toFixed(1)), Number(y1.toFixed(1)));
+				this.ctx.quadraticCurveTo(Number(x2.toFixed(1)), Number(y2.toFixed(1)), Number(x3.toFixed(1)), Number(y3
+					.toFixed(1)));
+				this.ctx.stroke();
+				this.ctx.draw && this.ctx.draw(true);
+			},
+			//画梯形
+			drawTrapezoid(point1, point2, point3, point4) {
+				this.ctx.beginPath();
+				this.ctx.moveTo(Number(point1.x.toFixed(1)), Number(point1.y.toFixed(1)));
+				this.ctx.lineTo(Number(point2.x.toFixed(1)), Number(point2.y.toFixed(1)));
+				this.ctx.lineTo(Number(point3.x.toFixed(1)), Number(point3.y.toFixed(1)));
+				this.ctx.lineTo(Number(point4.x.toFixed(1)), Number(point4.y.toFixed(1)));
+				this.ctx.setFillStyle && this.ctx.setFillStyle(this.lineColor);
+				this.ctx.fillStyle = this.lineColor;
+				this.ctx.fill();
+				this.ctx.draw && this.ctx.draw(true);
+			},
+			//获取弧度
+			getRadianData(x1, y1, x2, y2) {
+				var dis_x = x2 - x1;
+				var dis_y = y2 - y1;
+				if (dis_x === 0) {
+					return {
+						val: 0,
+						pos: -1
+					};
+				}
+				if (dis_y === 0) {
+					return {
+						val: 0,
+						pos: 1
+					};
+				}
+				var val = Math.abs(Math.atan(dis_y / dis_x));
+				if (x2 > x1 && y2 < y1 || x2 < x1 && y2 > y1) {
+					return {
+						val: val,
+						pos: 1
+					};
+				}
+				return {
+					val: val,
+					pos: -1
+				};
+			},
+			//获取弧度点
+			getRadianPoints(radianData, x, y, halfLineWidth) {
+				if (radianData.val === 0) {
+					if (radianData.pos === 1) {
+						return [{
+							x: x,
+							y: y + halfLineWidth
+						}, {
+							x: x,
+							y: y - halfLineWidth
+						}];
+					}
+					return [{
+						y: y,
+						x: x + halfLineWidth
+					}, {
+						y: y,
+						x: x - halfLineWidth
+					}];
+				}
+				var dis_x = Math.sin(radianData.val) * halfLineWidth;
+				var dis_y = Math.cos(radianData.val) * halfLineWidth;
+				if (radianData.pos === 1) {
+					return [{
+						x: x + dis_x,
+						y: y + dis_y
+					}, {
+						x: x - dis_x,
+						y: y - dis_y
+					}];
+				}
+				return [{
+					x: x + dis_x,
+					y: y - dis_y
+				}, {
+					x: x - dis_x,
+					y: y + dis_y
+				}];
+			},
+			/**
+			 * 背景色
+			 */
+			drawBgColor() {
+				if (!this.bgColor) return;
+				this.ctx.setFillStyle && this.ctx.setFillStyle(this.bgColor);
+				this.ctx.fillStyle = this.bgColor;
+				this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
+				this.ctx.draw && this.ctx.draw(true);
+			},
+			//图片绘制
+			drawByImage(url) {
+				this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+				try {
+					this.ctx.drawImage(url, 0, 0, this.canvasWidth * this.undoScan, this.canvasHeight * this.undoScan);
+					this.ctx.draw && this.ctx.draw(true);
+				} catch (e) {
+					this.historyList.length = 0;
+				}
+			},
+			/**
+			 * 清空
+			 */
+			clear() {
+				this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+				this.ctx.draw && this.ctx.draw();
+				this.drawBgColor();
+				this.historyList.length = 0;
+			},
+			//撤消
+			undo() {
+				if (!this.getImagePath || !this.historyList.length) return;
+				var pngURL = this.historyList.splice(-1)[0];
+				this.drawByImage(pngURL);
+				if (this.historyList.length === 0) {
+					this.clear();
+				}
+			},
+			//是否为空
+			isEmpty() {
+				return this.historyList.length === 0;
+			},
+			/**
+			 * @param {Object} str
+			 * @param {Object} color
+			 * 选择颜色
+			 */
+			selectColorEvent(str, color) {
+				this.selectColor = str;
+				this.lineColor = color;
+				this.ctx.setStrokeStyle(this.lineColor)
+			},
+
+			//完成
+			subCanvas() {
+				let that = this
+				if (that.isEmpty()) {
+					that.emptyShow = true
+					setTimeout(function() {
+						that.emptyShow = false
+					}, 1000)
+					return
+				}
+				uni.canvasToTempFilePath({
+					canvasId: that.canvasId,
+					fileType: 'png',
+					quality: 1, //图片质量
+					success(res) {
+						that.ctxs.translate(0, that.outSignHeight);
+						that.ctxs.rotate(-90 * Math.PI / 180)
+						that.ctxs.drawImage(res.tempFilePath, 0, 0, that.outSignHeight, that.outSignWidth)
+						that.ctxs.draw()
+						setTimeout(() => {
+							uni.canvasToTempFilePath({
+								canvasId: that.canvasIds,
+								fileType: 'png',
+								quality: 1, //图片质量
+								success: function(res1) {
+									if (that.action) {
+										uni.showLoading()
+										uni.uploadFile({
+											url: that.action, //图片上传post请求的地址
+											filePath: res1.tempFilePath,
+											name: "file",
+											header: that.header,
+											success: (uploadFileRes) => {
+												uni.hideLoading()
+												that.showImg = res1.tempFilePath
+												that.$emit('signToUrl',
+													uploadFileRes)
+												that.signModShow = false
+												that.clear()
+											},
+											fail: (error) => {
+												uni.hideLoading()
+											}
+										});
+									} else {
+										that.showImg = res1.tempFilePath
+										that.$emit('signToUrl', {
+											error_code: "201",
+											msg: "请配置上传文件接口参数action"
+										})
+										that.signModShow = false
+										that.clear()
+									}
+								},
+								fail: (err) => {}
+							}, that)
+						}, 200);
+					}
+				}, this);
+			},
+			//保存到相册
+			saveCanvasAsImg() {
+				uni.canvasToTempFilePath({
+					canvasId: this.canvasId,
+					fileType: 'png',
+					quality: 1, //图片质量
+					success(res) {
+						uni.saveImageToPhotosAlbum({
+							filePath: res.tempFilePath,
+							success(res) {
+								uni.showToast({
+									title: '已保存到相册',
+									duration: 2000
+								});
+							}
+						});
+					}
+				}, this);
+			},
+			//预览
+			previewCanvasImg() {
+				uni.canvasToTempFilePath({
+					canvasId: this.canvasId,
+					fileType: 'jpg',
+					quality: 1, //图片质量
+					success(res) {
+						uni.previewImage({
+							urls: [res.tempFilePath] //预览图片 数组
+						});
+					}
+				}, this);
+			},
+			deleteImg() {
+				this.showImg = ""
+			},
+
+			previewImg(img) {
+				uni.previewImage({
+					urls: [img] //预览图片 数组
+				});
+			},
+
+		}
+	};
+</script>
+
+<style lang="scss">
+	page {
+		background: #d9d9d9;
+		height: auto;
+		overflow: hidden;
+	}
+
+	.imgBox {
+		width: 140px;
+		height: 80px;
+		position: relative;
+
+		.nom_img {
+			border-radius: 8px;
+			border: 1px dashed;
+			border-color: #a3a3a3;
+			overflow: hidden;
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			height: 80px;
+			width: 140px;
+		}
+
+		.nom_img:hover {
+			border-color: #008ef6 !important;
+		}
+
+		.across_img {
+			border: 1px dashed #a3a3a3;
+			border-radius: 8px;
+			height: 80px;
+			width: 140px;
+
+			.delete_icon {
+				position: absolute;
+				top: -12px;
+				right: -12px;
+				width: 24px;
+				height: 24px;
+				overflow: hidden;
+				color: #ffffff;
+				font-size: 24px;
+				text-align: center;
+				line-height: 20px;
+				background: #ff3c0c;
+				border-radius: 25px;
+				z-index: 1;
+			}
+		}
+	}
+
+	.warp {
+		width: 100%;
+		height: 100vh;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+
+		.signBox {
+			width: 85vw;
+			height: 85vh;
+			background: #ffffff;
+			border-radius: 8px;
+		}
+	}
+
+	.wrapper {
+		width: 85vw;
+		height: 85vh;
+		overflow: hidden;
+		display: flex;
+		align-content: center;
+		flex-direction: row;
+		justify-content: center;
+		font-size: 28rpx;
+	}
+
+	.handRight {
+		display: inline-flex;
+		align-items: center;
+	}
+
+	.handCenter {
+		position: fixed;
+		border: 4rpx dashed #e9e9e9;
+		flex: 5;
+		margin-top: 4rpx;
+		overflow: hidden;
+		box-sizing: border-box;
+		width: calc(100% - 84rpx - 200rpx);
+		height: calc(85vh - 8rpx)
+	}
+
+	.handCenters {
+		position: fixed;
+		top: 0;
+		left: 10000rpx;
+		flex: 5;
+		overflow: hidden;
+		box-sizing: border-box;
+	}
+
+
+	.handTitle {
+		transform: rotate(90deg);
+		flex: 1;
+		color: #666;
+	}
+
+	.handBtn button {
+		font-size: 28rpx;
+	}
+
+	.handBtn {
+		height: 85vh;
+		display: inline-flex;
+		flex-direction: column;
+		justify-content: space-between;
+		align-content: space-between;
+		flex: 1;
+	}
+
+	.delBtn {
+		position: absolute;
+		top: 380rpx;
+		left: 46rpx;
+		transform: rotate(90deg);
+		color: #666;
+	}
+
+	.subBtn {
+		position: absolute;
+		bottom: 158rpx;
+		left: 46rpx;
+		display: inline-flex;
+		transform: rotate(90deg);
+		background: #008ef6;
+		color: #fff;
+		text-align: center;
+		justify-content: center;
+	}
+
+	/*Peach - 新增 - 保存*/
+
+	.saveBtn {
+		position: absolute;
+		top: 650rpx;
+		left: 46rpx;
+		transform: rotate(90deg);
+		color: #666;
+	}
+
+	.previewBtn {
+		position: absolute;
+		top: 516rpx;
+		left: 46rpx;
+		transform: rotate(90deg);
+		color: #666;
+	}
+
+	.undoBtn {
+		position: absolute;
+		top: 780rpx;
+		left: 46rpx;
+		transform: rotate(90deg);
+		color: #666;
+	}
+
+	.emptyInfo {
+		position: absolute;
+		bottom: 418rpx;
+		left: -56rpx;
+		transform: rotate(90deg);
+		color: #666;
+	}
+
+	.color_pic {
+		width: 70rpx;
+		height: 70rpx;
+		border-radius: 25px;
+		position: absolute;
+		top: 200rpx;
+		left: 62rpx;
+		border: 1px solid #ddd;
+	}
+
+	/*Peach - 新增 - 保存*/
+
+	.black-select {
+		width: 60rpx;
+		height: 60rpx;
+		position: absolute;
+		top: 150rpx;
+		left: 70rpx;
+	}
+
+	.red-select {
+		width: 60rpx;
+		height: 60rpx;
+		position: absolute;
+		top: 260rpx;
+		left: 70rpx;
+	}
+</style>

+ 143 - 0
jp-mobile/components/am-sign-input/pickerColor.vue

@@ -0,0 +1,143 @@
+<template>
+	<view v-show="isShow">
+		<view class="shade" @tap="hide">
+			<view class="pop">
+				<view class="list flex_col" v-for="(item,index) in colorArr" :key="index">
+					<view v-for="(v,i) in item" :key="i" :style="{'backgroundColor':v}" :data-color="v"
+						:data-index="index" :data-i="i" :class="{'active':(index==pickerArr[0] && i==pickerArr[1])}"
+						@tap.stop="picker"></view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'picker-color',
+		props: {
+			isShow: {
+				type: Boolean,
+				default: false,
+			},
+			bottom: {
+				type: Number,
+				default: 0,
+			}
+		},
+		data() {
+			return {
+				colorArr: [
+					['#000000', '#111111', '#222222', '#333333', '#444444', '#666666', '#999999', '#CCCCCC', '#EEEEEE',
+						'#FFFFFF'
+					],
+					['#ff0000', '#ff0033', '#ff3399', '#ff33cc', '#cc00ff', '#9900ff', '#cc00cc', '#cc0099', '#cc3399',
+						'#cc0066'
+					],
+					['#cc3300', '#cc6600', '#ff9933', '#ff9966', '#ff9999', '#ff99cc', '#ff99ff', '#cc66ff', '#9966ff',
+						'#cc33ff'
+					],
+					['#663300', '#996600', '#996633', '#cc9900', '#a58800', '#cccc00', '#ffff66', '#ffff99', '#ffffcc',
+						'#ffcccc'
+					],
+					['#336600', '#669900', '#009900', '#009933', '#00cc00', '#66ff66', '#339933', '#339966', '#009999',
+						'#33cccc'
+					],
+					['#003366', '#336699', '#3366cc', '#0099ff', '#000099', '#0000cc', '#660066', '#993366', '#993333',
+						'#800000'
+					]
+				],
+				pickerColor: '',
+				pickerArr: [-1, -1]
+			};
+		},
+		methods: {
+			picker(e) {
+				let data = e.currentTarget.dataset;
+				this.pickerColor = data.color;
+				this.pickerArr = [data.index, data.i];
+				this.$emit("callback", this.pickerColor);
+			},
+			hide() {
+				this.$emit("callback", '');
+			},
+		},
+	}
+</script>
+
+<style scoped>
+	.shade {
+		position: fixed;
+		top: 0;
+		right: 0;
+		bottom: 0;
+		left: 0;
+		background-color: rgba(0, 0, 0, 0.5);
+		z-index: 10080;
+		display: flex;
+		justify-content: center;
+		align-items: center
+	}
+
+	.pop {
+		border-radius: 8px;
+		background-color: #fff;
+		z-index: 100;
+		padding: 12upx;
+		font-size: 32upx;
+		transform: rotate(90deg);
+	}
+
+	.flex_col {
+		display: flex;
+		flex-direction: row;
+		flex-wrap: nowrap;
+		justify-content: flex-start;
+		align-items: center;
+		align-content: center;
+	}
+
+	.list {
+		justify-content: space-between;
+	}
+
+	.list>view {
+		width: 60upx;
+		height: 60upx;
+		margin: 5upx;
+		box-sizing: border-box;
+		border-radius: 3px;
+		box-shadow: 0 0 2px #ccc;
+	}
+
+	.list .active {
+		box-shadow: 0 0 2px #09f;
+		transform: scale(1.05, 1.05);
+	}
+
+	.preview {
+		width: 180upx;
+		height: 60upx;
+	}
+
+	.value {
+		margin: 0 40upx;
+		flex-grow: 1;
+	}
+
+	.ok {
+		width: 160upx;
+		height: 60upx;
+		line-height: 60upx;
+		text-align: center;
+		background-color: #ff9933;
+		color: #fff;
+		border-radius: 4px;
+		letter-spacing: 3px;
+		font-size: 32upx;
+	}
+
+	.ok:active {
+		background-color: rgb(255, 107, 34);
+	}
+</style>

+ 124 - 0
jp-mobile/components/am-sign-input/u-mask/u-mask.vue

@@ -0,0 +1,124 @@
+<template>
+	<view class="u-mask" hover-stop-propagation :style="[maskStyle, zoomStyle]" @tap="click"
+		@touchmove.stop.prevent="() => {}" :class="{
+		'u-mask-zoom': zoom,
+		'u-mask-show': show
+	}">
+		<slot />
+	</view>
+</template>
+
+<script>
+	/** 
+	 * mask 遮罩
+	 * @description 创建一个遮罩层,用于强调特定的页面元素,并阻止用户对遮罩下层的内容进行操作,一般用于弹窗场景
+	 * @tutorial https://www.uviewui.com/components/mask.html
+	 * @property {Boolean} show 是否显示遮罩(默认false)
+	 * @property {String Number} z-index z-index 层级(默认1070)
+	 * @property {Object} custom-style 自定义样式对象,见上方说明
+	 * @property {String Number} duration 动画时长,单位毫秒(默认300)
+	 * @property {Boolean} zoom 是否使用scale对遮罩进行缩放(默认true)
+	 * @property {Boolean} mask-click-able 遮罩是否可点击,为false时点击不会发送click事件(默认true)
+	 * @event {Function} click mask-click-able为true时,点击遮罩发送此事件
+	 * @example <u-mask :show="show" @click="show = false"></u-mask>
+	 */
+	export default {
+		name: "u-mask",
+		props: {
+			// 是否显示遮罩
+			show: {
+				type: Boolean,
+				default: false
+			},
+			// 层级z-index
+			zIndex: {
+				type: [Number, String],
+				default: '10070'
+			},
+			// 用户自定义样式
+			customStyle: {
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			// 遮罩的动画样式, 是否使用使用zoom进行scale进行缩放
+			zoom: {
+				type: Boolean,
+				default: true
+			},
+			// 遮罩的过渡时间,单位为ms
+			duration: {
+				type: [Number, String],
+				default: 300
+			},
+			// 是否可以通过点击遮罩进行关闭
+			maskClickAble: {
+				type: Boolean,
+				default: true
+			}
+		},
+		data() {
+			return {
+				zoomStyle: {
+					transform: ''
+				},
+				scale: 'scale(1.2, 1.2)'
+			}
+		},
+		watch: {
+			show(n) {
+				if (n && this.zoom) {
+					// 当展示遮罩的时候,设置scale为1,达到缩小(原来为1.2)的效果
+					this.zoomStyle.transform = 'scale(1, 1)';
+				} else if (!n && this.zoom) {
+					// 当隐藏遮罩的时候,设置scale为1.2,达到放大(因为显示遮罩时已重置为1)的效果
+					this.zoomStyle.transform = this.scale;
+				}
+			}
+		},
+		computed: {
+			maskStyle() {
+				let style = {};
+				style.backgroundColor = "rgba(0, 0, 0, 0.6)";
+				if (this.show) style.zIndex = this.zIndex ? this.zIndex : this.$u.zIndex.mask;
+				else style.zIndex = -1;
+				style.transition = `all ${this.duration / 1000}s ease-in-out`;
+				// 判断用户传递的对象是否为空,不为空就进行合并
+				if (Object.keys(this.customStyle).length) style = {
+					...style,
+					...this.customStyle
+				};
+				return style;
+			}
+		},
+		methods: {
+			click() {
+				if (!this.maskClickAble) return;
+				this.$emit('click');
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	// @import "../../libs/css/style.components.scss";
+
+	.u-mask {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		opacity: 0;
+		transition: transform 0.3s;
+	}
+
+	.u-mask-show {
+		opacity: 1;
+	}
+
+	.u-mask-zoom {
+		transform: scale(1.2, 1.2);
+	}
+</style>

+ 2 - 2
jp-mobile/components/jp-datetime-picker/jp-datetime-picker.vue

@@ -12,8 +12,8 @@
 			></u-datetime-picker>
 			<u--input
 				v-model="label"
-				suffixIcon="arrow-right"
-				suffixIconStyle="color: #909399"
+				suffixIcon="calendar"
+				suffixIconStyle="color: #17a2f8"
 				disabled
 				disabledColor="#ffffff"
 				:placeholder="placeholder"

+ 2 - 2
jp-mobile/components/jp-picker/jp-picker.vue

@@ -3,8 +3,8 @@
 		<picker style="width: 100%;" @change="PickerChange" :value="index" :disabled="disabled" :range-value="rangeValue"  :range-key="rangeKey" :range="range">
 		<u--input
 			v-model="label"
-			suffixIcon="arrow-right"
-			suffixIconStyle="color: #909399"
+			suffixIcon="arrow-down"
+			suffixIconStyle="color: #17a2f8"
 			disabled
 			disabledColor="#ffffff"
 			placeholder="请选择"

+ 223 - 0
jp-mobile/components/office-user-select/office-user-select.vue

@@ -0,0 +1,223 @@
+<template>
+	<view style="width: 100%;" @tap="open">
+		<u--input v-model="labels" suffixIcon="arrow-right" suffixIconStyle="color: #909399" disabled
+			disabledColor="#ffffff" :placeholder="placeholder" border="none"></u--input>
+
+		<u-action-sheet :show="show" @close="show = false">
+			<view class="cu-bar bg-white">
+				<view class="action text-blue" @tap="show=false">取消</view>
+				<view>{{title}}</view>
+				<view class="action text-green" @tap="selectUser">确定</view>
+			</view>
+			<view class="allsrc">
+				<scroll-view scroll-y class="src1">
+					<view v-for="item in tab1" class="tab1" @click="tab1click(item)">
+						<text :class="item.id==index1?'tab1_seltext':'tab1_text '"
+							class="tab1_text">{{ item.name }}</text>
+						<u-badge :absolute="true" :offset="[0,0]" type="primary" :value="getSelect(item.id)"></u-badge>
+					</view>
+				</scroll-view>
+				<scroll-view scroll-y class="src2">
+					<view class="tab2">
+						<view class="tab2_text" v-for="item in tab2" @click="tab1click2(item)"
+							:class="item.check?'current':''">
+							{{item.name}}
+						</view>
+					</view>
+				</scroll-view>
+			</view>
+		</u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import officeService from "@/api/sys/officeService"
+	import userService from "@/api/sys/userService"
+	export default {
+		data() {
+			return {
+				index1: "",
+				tab1: [],
+				tab2: [],
+				labels: '',
+				show: false,
+				data: [],
+				selectList: [],
+				userList: [],
+			}
+		},
+		props: {
+			limit: Number,
+			value: String,
+			size: String,
+			placeholder: String,
+			title: String,
+			readonly: {
+				type: Boolean,
+				default: () => {
+					return false
+				}
+			},
+			checkOnlyLeaf: {
+				type: Boolean,
+				default: () => {
+					return false
+				}
+			},
+			showRadio: {
+				type: Boolean,
+				default: () => {
+					return true
+				}
+			},
+			showCheckBox: {
+				type: Boolean,
+				default: () => {
+					return false
+				}
+			},
+			disabled: {
+				type: Boolean,
+				default: () => {
+					return false
+				}
+			},
+			props: {
+				type: Object,
+				default: () => {
+					return {
+						children: 'children',
+						label: 'name'
+					}
+				}
+			}
+		},
+		mounted() {
+			officeService.treeData({
+				parentId: "1771063850830143489"
+			}).then((data) => {
+				this.tab1 = data
+				this.index1 = data[0].id
+				userService.officeList().then(res => {
+					this.userList = res
+					this.userList = this.userList.map(item => ({
+						...item,
+						check: false
+					}));
+					this.tab1click(this.tab1[0])
+				})
+			})
+
+		},
+		methods: {
+			open() {
+				this.show = true;
+
+				if (this.value) {
+					console.log("user=======",this.value);
+					let u = this.value.split(",")
+					this.$nextTick(() => {
+						for (let i = 0; i < this.userList.length; i++) {
+							let b = u.filter(t => t==this.userList[i].id)
+							if(b.length>0) {
+								this.$set(this.userList[i], "check", true);
+								this.selectList.push(this.userList[i])
+							}
+						}
+					})
+				}
+			},
+
+			selectUser() {
+				let ids = this.selectList.map((item) => {
+					return item.id
+				}).join(",");
+				let names = this.selectList.map((item) => {
+					return item.name
+				}).join(",");
+				this.labels = names
+				this.$emit('input', ids)
+				this.show = false
+			},
+			tab1click(e) {
+				this.index1 = e.id;
+				this.tab2 = this.userList.filter(item => item.officeDTO.id == e.id)
+
+			},
+			tab1click2(item) {
+				item.check = !item.check
+				if (item.check) {
+					this.selectList.push(item)
+				} else {
+					this.selectList = this.selectList.filter(e => item.id != e.id)
+				}
+			},
+			getSelect(id) {
+				let s = this.selectList.filter(item => item.officeDTO.id == id)
+				return s.length
+			}
+		}
+	}
+</script>
+
+<style>
+	.allsrc {
+		display: flex;
+		height: 60vh;
+	}
+
+	.src1 {
+		flex: 1;
+		background: #f5f5f5;
+	}
+
+	.tab1 {
+		height: 80rpx;
+		color: black;
+		text-align: center;
+		justify-content: center;
+		align-items: center;
+		display: flex;
+		position: relative;
+	}
+
+	.tab1_seltext {
+		background: #fff;
+		padding: 16rpx 40rpx;
+		width: 100%;
+	}
+
+	.src2 {
+		flex: 2;
+		background: #fff;
+		margin-left: 3rpx;
+		margin-right: 3rpx;
+		height: 100%;
+	}
+
+	.tab2 .u-button {
+		width: 40% !important;
+		float: left;
+		margin: 20rpx;
+	}
+
+	.describle {
+		text-align: center;
+		font-size: 22rpx;
+		color: #5ac775;
+		height: 40px;
+		line-height: 40px;
+	}
+
+
+
+	.tab2_text {
+		height: 40px;
+		font-size: 14px;
+		line-height: 40px;
+	}
+
+	.tab2 .current {
+		color: #36a7f3;
+	}
+</style>

+ 1 - 1
jp-mobile/config.js

@@ -8,6 +8,6 @@ if(process.env.NODE_ENV === 'development'){
     APP_SERVER_URL = 'http://vue3.jeeplus.org/jeeplus-v3/api'
 }
 
-APP_SERVER_URL = APP_SERVER_URL + '/app'
+// APP_SERVER_URL = APP_SERVER_URL + '/app'
 
 export default APP_SERVER_URL

+ 19 - 19
jp-mobile/package.json

@@ -1,20 +1,20 @@
 {
-  "name": "ColorUI-UniApp",
-  "version": "1.0.0",
-  "description": "<p style=\"text-align: center;\"><img src=\"https://image.weilanwl.com/uni/UniAppReadme.jpg\" alt=\"ColorUI简介\"></img></p>",
-  "main": "main.js",
-  "dependencies": {
-    "lodash": "^4.17.20",
-    "lodash.pick": "^4.4.0",
-    "moment": "^2.27.0",
-    "prettier": "^1.12.1",
-    "qs": "^6.9.4"
-  },
-  "devDependencies": {},
-  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
-  },
-  "keywords": [],
-  "author": "",
-  "license": "ISC"
-}
+    "id": "am-sign-input",
+    "name": "电子签名输入框",
+    "displayName": "电子签名输入框",
+    "version": "0.0.7",
+    "description": "用于canvas电子签名生成图片(可配置上传接口生成图片地址,配置生成图片大小) 毛笔字  笔锋",
+    "keywords": [
+        "电子签名",
+        "签名上传",
+        "签名",
+        "毛笔字",
+        "笔锋"
+    ],
+    "dcloudext": {
+        "category": [
+            "前端组件",
+            "通用组件"
+        ]
+    }
+}

+ 31 - 1
jp-mobile/pages.json

@@ -12,6 +12,36 @@
 			"style": {
 				"navigationStyle": "custom" // 隐藏系统导航栏
 			}
+		}
+		,{
+		    "path" : "pages/fileTransmit/addFileTransmit",
+		    "style" : {
+				"navigationBarTitleText": "新增文件传阅卡"
+			}
+		},
+		{
+		    "path" : "pages/fileTransmit/examineFile",
+		    "style" : {
+				"navigationBarTitleText": "审批页"
+			}
+		},
+		{
+		    "path" : "pages/fileTransmit/fileInfo",
+		    "style" : {
+				"navigationBarTitleText": "公文详情"
+			}
+		},
+		{
+		    "path" : "pages/fileTransmit/fileTransmitList",
+		    "style" : {
+				"navigationBarTitleText": "文件传阅卡"
+			}
+		},
+		{
+		    "path" : "pages/fileTransmit/statistics",
+		    "style" : {
+				"navigationBarTitleText": "公文统计"
+			}
 		},
 		{
 			"path": "pages/user/setting/password/password",
@@ -581,7 +611,7 @@
 	  "usingComponents": {
 				"ly-tree-node": "/components/ly-tree/ly-tree-node"
 			},
-		"navigationBarBackgroundColor": "#0081ff",
+		"navigationBarBackgroundColor": "#36a7f3",
 		"navigationBarTitleText": "Jeeplus 移动审批",
 		// "navigationStyle": "custom",
 		"navigationBarTextStyle": "white"

+ 196 - 0
jp-mobile/pages/fileTransmit/addFileTransmit.vue

@@ -0,0 +1,196 @@
+<template>
+	<view>
+		<view class="bg-white default_title">
+			<u--form :model="inputForm" labelWidth="130px" class="u-form default_title" labelPosition="left"
+				ref="inputForm">
+				<u-form-item label="年度" borderBottom prop="yearNum">
+					<u--input placeholder="输入年度" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="卡号" borderBottom prop="cardNum">
+					<u--input placeholder="输入卡号" border="none"></u--input>
+				</u-form-item>
+			</u--form>
+		</view>
+		<view class="bg-white margin-top main_info">
+			<u--form :model="inputForm" labelWidth="130px" class="u-form default_title" labelPosition="left"
+				ref="inputForm">
+				<u-form-item label="来文机关" borderBottom prop="sendingAgency">
+					<u--input v-model="inputForm.sendingAgency" placeholder="请输入来文机关" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="来文字号" borderBottom prop="docFontSize">
+					<u--input v-model="inputForm.docFontSize" placeholder="请输入来文字号" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="文件来源" borderBottom prop="fileSource">
+					<u--input v-model="inputForm.fileSource" placeholder="请输入文件来源" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="成文时间" borderBottom prop="writtenTime">
+					<jp-datetime-picker v-model="inputForm.writtenTime" placeholder="选择成文时间"
+						mode="datetime"></jp-datetime-picker>
+				</u-form-item>
+				<u-form-item label="收文时间" borderBottom prop="receivingTime">
+					<jp-datetime-picker v-model="inputForm.receivingTime" placeholder="选择收文时间"
+						mode="datetime"></jp-datetime-picker>
+				</u-form-item>
+				<u-form-item label="内容摘要" borderBottom prop="contentSummary">
+					<u--textarea v-model="inputForm.contentSummary" placeholder="请输入内容摘要" border="none"></u--textarea>
+				</u-form-item>
+				<u-form-item label="来文附件" prop="attachedDocumentId" labelPosition="top">
+					<u-upload :fileList="fileLists" @afterRead="afterRead" @delete="deletePic" multiple :maxCount="9"
+						width="250" height="150" accept="file" :previewImage="false">
+						<view class="addfile flex"> <u-icon size="20" bold name="plus"></u-icon></view>
+					</u-upload>
+				</u-form-item>
+				<view class="other_info" v-for="item in fileList">
+					<view class="other_pdf">
+						<u--text mode="link" :text="item.name" :href="item.url"></u--text>
+					</view>
+				</view>
+				<u-upload :fileList="imgList" multiple :maxCount="imgList.length" :previewFullImage="true"></u-upload>
+				<u--text size="12" type="error" text="请确保上传图片内容清晰可见,所有涉密敏感信息不得上传"></u--text>
+				<view class="submit_btn flex">
+					<u-button type="primary" text="提交新增" @click="formSubmit"></u-button>
+				</view>
+			</u--form>
+
+
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		isImageFormat
+	} from "@/common/util.js"
+	import gwCirculationCard2Service from '@/api/circulation/gwCirculationCard2.js'
+	export default {
+		data() {
+			return {
+				fileLists: [],
+				fileList: [],
+				imgList: [],
+				inputForm: {
+					id: '',
+					yearNum: '',
+					cardNum: '',
+					sendingAgency: '',
+					docFontSize: '',
+					fileSource: '',
+					writtenTime: '',
+					receivingTime: '',
+					contentSummary: '',
+					attachedDocumentId: '',
+					remark: '',
+					state: '1'
+				},
+			}
+		},
+		methods: {
+			// 新增图片
+			async afterRead(event) {
+				// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
+				let lists = [].concat(event.file)
+				let fileListLen = this.fileLists.length
+				lists.map((item) => {
+					this.fileLists.push({
+						...item,
+						status: 'uploading',
+						message: '上传中'
+					})
+				})
+				for (let i = 0; i < lists.length; i++) {
+					const result = await this.uploadFilePromise(lists[i].url)
+					// const result = "https://cdn.uviewui.com/uview/album.pdf"
+					let item = this.fileLists[fileListLen]
+					this.fileLists.splice(fileListLen, 1, Object.assign(item, {
+						status: 'success',
+						message: '',
+						url: result
+					}))
+					fileListLen++
+					if (isImageFormat(item.url)) {
+						this.imgList.push(item)
+					} else {
+						const fileName = item.url.split(/[/\\]/).pop();
+						let a = {
+							name: fileName,
+							url: item.url
+						}
+						this.fileList.push(a)
+					}
+				}
+			},
+			uploadFilePromise(url) {
+				return new Promise((resolve, reject) => {
+					let a = uni.uploadFile({
+						url: 'http://192.168.2.21:7001/upload', // 仅为示例,非真实的接口地址
+						filePath: url,
+						name: 'file',
+						formData: {
+							user: 'test'
+						},
+						success: (res) => {
+							setTimeout(() => {
+								resolve(res.data.data)
+							}, 1000)
+						}
+					});
+				})
+			},
+			// 表单提交
+			formSubmit() {
+				// this.$refs['inputForm'].validate((valid) => {
+				// 	if (valid) {
+						gwCirculationCard2Service.save(this.inputForm).then((data) => {
+							
+							this.$message.success(data)
+							 uni.reLaunch({
+							        url: '/pages/fileTransmit/addFileTransmit' 
+							      });
+						}).catch(() => {
+							
+						})
+				// 	}
+				// })
+			}
+
+		}
+	}
+</script>
+
+<style>
+	.default_title {
+		padding-top: 0px;
+	}
+
+	.main_info {
+		margin-top: 15px;
+		/* height: 80vh; */
+	}
+
+	.submit_btn {
+		background-color: #fefefe;
+		margin-top: 20px;
+		box-shadow: none;
+		margin-bottom: 20px;
+	}
+
+	.submit_btn button {
+		height: 40px;
+		width: 80%;
+		border-radius: 30px;
+
+	}
+
+	.addfile {
+		width: 80px;
+		height: 80px;
+		background-color: #eee;
+		padding-left: 30%;
+		/* padding-left: 18%; */
+		margin: 10px;
+	}
+
+	.other_info {
+		width: 100%;
+	}
+</style>

+ 142 - 0
jp-mobile/pages/fileTransmit/examineFile.vue

@@ -0,0 +1,142 @@
+<template>
+	<view class="office_page">
+		<fileCard :isoffice="isoffice" :isleader="isleader" :isinfo="true"></fileCard>
+		<view class="office_main">
+			<view class="office_title">
+				<uni-section v-if="isoffice" titleColor="#36a7f3" class="mb-10" title="办公室拟办" type="line"></uni-section>
+				<uni-section v-if="isleader" titleColor="#36a7f3" class="mb-10" title="领导批示" type="line"></uni-section>
+			</view>
+			<view class="office_info">
+				<u--form v-if="isoffice" :model="auditForm" labelWidth="130px" class="u-form default_title"
+					labelPosition="left" ref="auditForm">
+					<u-form-item label="办公室拟办" borderBottom prop="title">
+						<u--textarea placeholder=""></u--textarea>
+					</u-form-item>
+					<u-form-item label="转发领导" borderBottom prop="teDate">
+						<jp-picker placeholder="请选择转发领导" :range="leaderList" rangeKey="name" rangeValue="id"></jp-picker>
+					</u-form-item>
+					<u-form-item label="科室承办" borderBottom prop="teDate">
+						<office-user-select  placeholder="请选择科室承办" title="科室承办"></office-user-select>
+					</u-form-item>
+					<u-form-item label="备注" borderBottom prop="message">
+						<u--input placeholder="请输入备注" border="none"></u--input>
+					</u-form-item>
+					<view class="submit_btn flex ">
+						<!-- <u-button @click="formSubmit" color="#36a7f3" plain hairline type="primary" text="暂存待办"></u-button> -->
+						<u-button disabled="" type="primary" text="确认签字"></u-button>
+					</view>
+				</u--form>
+				<u--form v-if="isleader" :model="auditForm" labelWidth="130px" class="u-form default_title"
+					labelPosition="left" ref="auditForm">
+					<u-form-item label="领导批示" borderBottom prop="title">
+						<u--textarea placeholder=""></u--textarea>
+					</u-form-item>
+					<view class="submit_btn flex ">
+						<u-button disabled="" type="primary" text="确认签字"></u-button>
+					</view>
+				</u--form>
+				<!-- <signInput ref="sign" canvasId="twoDrowCanvas" canvasIds="twoRotateCanvas" :header="header"
+					:action="action" @signToUrl="signToUrl">
+				</signInput> -->
+			</view>
+		</view>
+	</view>
+
+</template>
+
+<script>
+	import fileCard from "./fileCard.vue"
+	import signInput from "@/components/am-sign-input/am-sign-input.vue"
+	import officeUserSelect from "@/components/office-user-select/office-user-select.vue"
+	import userService from "@/api/sys/userService"
+	export default {
+		components: {
+			fileCard,
+			signInput,
+			officeUserSelect
+		},
+		mounted() {
+			this.searchForm.officeDTO.id="1770354910488272897"
+			userService.list({
+				current: this.tablePage.currentPage,
+				size: this.tablePage.pageSize,
+				orders: this.tablePage.orders,
+				...this.searchForm
+			}).then(data => {
+				console.log("user=============", data);
+				this.leaderList = data.records
+			})
+		},
+		data() {
+			return {
+				action: "", //上传服务器的地址
+				header: {}, //图片上传携带头部信息
+				auditForm: {},
+				isoffice: true,
+				isleader: false,
+				leaderList: [],
+				tablePage: {
+					total: 0,
+					currentPage: 1,
+					pageSize: 1000,
+					orders: [{
+						column: "a.create_time",
+						asc: false
+					}],
+				},
+				searchForm: {
+					loginName: "",
+					name: "",
+					companyDTO: {
+						id: "",
+					},
+					officeDTO: {
+						id: "",
+					},
+				},
+			}
+		},
+		methods: {
+			/**
+			 * @param {Object} e
+			 * 签名完成回调
+			 */
+			signToUrl(e) {
+				if (e.error_code && e.error_code === '201') {
+					uni.showToast({
+						title: e.msg,
+						icon: 'none'
+					})
+					return
+				}
+			},
+		}
+	}
+</script>
+
+<style>
+	.office_main {
+		width: 100%;
+		margin: 5px 0;
+		padding: 0 20px;
+		background-color: #fefefe;
+	}
+
+	.office_main .office_title {
+		width: 100%;
+		border-bottom: 1px solid #eee;
+	}
+
+	.submit_btn {
+		background-color: #fefefe;
+		bottom: 10px;
+		box-shadow: none;
+		padding: 20px 0;
+	}
+
+	.submit_btn button {
+		height: 40px;
+		width: 40%;
+		border-radius: 30px;
+	}
+</style>

+ 249 - 0
jp-mobile/pages/fileTransmit/fileCard.vue

@@ -0,0 +1,249 @@
+<template>
+	<view class="card_main">
+		<view class="card_banner"></view>
+		<view class="card_info">
+			<view class="card_info_title">
+				盐都工信文件阅办卡
+			</view>
+			<view class="card_table">
+				<u-row justify="space-between">
+					<u-col span="6">
+						<view>年度: 2024</view>
+					</u-col>
+					<u-col span="6">
+						<view style="text-align: right;">[2024]001号</view>
+					</u-col>
+				</u-row>
+				<u-row justify="space-between" class="card_row">
+					<u-col span="3" textAlign="center" class="card_col">
+						<view>来文机关</view>
+					</u-col>
+					<u-col span="3" textAlign="center" class="card_col">
+						<view>[2024]001号</view>
+					</u-col>
+					<u-col span="3" textAlign="center" class="card_col">
+						<view>来文字号</view>
+					</u-col>
+					<u-col span="3" textAlign="center">
+						<view>[2024]001号</view>
+					</u-col>
+				</u-row>
+				<u-row justify="space-between" class="card_row card_row_border">
+					<u-col span="3" textAlign="center" class="card_col">
+						<view>收文时间</view>
+					</u-col>
+					<u-col span="3" textAlign="center" class="card_col">
+						<view>[2024]001号</view>
+					</u-col>
+					<u-col span="3" textAlign="center" class="card_col">
+						<view>文件来源</view>
+					</u-col>
+					<u-col span="3" textAlign="center">
+						<view>[2024]001号</view>
+					</u-col>
+				</u-row>
+				<u-row justify="space-between" class="card_row card_row_border">
+					<u-col span="3" textAlign="center" align="center">
+						<view>内容摘要</view>
+					</u-col>
+					<u-col span="9" class="info_abstract">
+						<view class="info_abstract_v">
+							[2024]001号11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
+						</view>
+					</u-col>
+				</u-row>
+				<u-row v-if="isleader || isinfo" style="height: 70px;" justify="space-between" class="card_row card_row_border">
+					<u-col span="1" textAlign="center" >
+						<view class="vertical-text">办公室拟办</view>
+					</u-col>
+					<u-col  span="11" class="info_abstract">
+						<view class="info_abstract_v">
+							<view >
+								请领导长阅,承办地方阅处。
+							</view>
+							<view class="flex " style="line-height: 20px;">
+								<u--image :src="src" width="80px" height="20px"></u--image>
+								2024-3-21 00:00
+							</view>
+						</view>
+							
+							
+					</u-col>
+				</u-row>
+				<u-row v-if="isinfo" justify="space-between" class="card_row card_row_border">
+					<u-col span="1" textAlign="center" >
+						<view class="vertical-text">领导批示</view>
+					</u-col>
+					<u-col  span="11" class="info_abstract">
+						<view class="info_abstract_v">
+							<view >
+								请领导长阅,承办地方阅处。
+							</view>
+							<view class="flex " style="line-height: 20px;">
+								<u--image :src="src" width="80px" height="20px"></u--image>
+								2024-3-21 00:00
+							</view>
+						</view>
+					</u-col>
+				</u-row>
+				<u-row v-if="isinfo"  justify="space-between" class="card_row card_row_border">
+					<u-col span="1" textAlign="center" >
+						<view class="vertical-text">承办情况</view>
+					</u-col>
+					<u-col  span="11" class="info_abstract">
+						<view class="info_abstract_v">
+							承办地方      2024-3-21 00:00
+						</view>
+					</u-col>
+				</u-row>
+				<u-row v-if="isinfo" justify="space-between" class="card_row card_row_border">
+					<u-col span="3" textAlign="center" class="card_col">
+						<view>备注</view>
+					</u-col>
+					<u-col span="9" textAlign="center" >
+						<view>[2024]001号</view>
+					</u-col>
+				</u-row>
+				<u--text style="margin: 10px;" size="12" type="error" text="所有涉密敏感信息不得上传"></u--text>
+				<view class="card_other">
+					附件:
+					<view class="other_info" v-for="item in fileList">
+						<view class="other_pdf  flex  ">
+							<u--text mode="link" :text="item.name" :href="item.url" ></u--text>
+						</view>
+					</view>
+					<u-upload
+						:fileList="imgList"
+						name="3"
+						multiple
+						:maxCount="imgList.length"
+						:previewFullImage="true"
+						:deletable="false"
+					></u-upload>
+				</view>
+			</view>
+
+		</view>
+	</view>
+</template>
+
+<script>
+	import {isImageFormat} from "@/common/util.js"
+	export default {
+		mounted() {
+			this.fileLists.forEach(item =>{
+				if(isImageFormat(item.url)){
+					this.imgList.push(item)
+				}else{
+					const fileName = item.url.split(/[/\\]/).pop();
+					let a = {
+						name: fileName,
+						url:item.url
+					}
+					this.fileList.push(a)
+				}
+			})
+		},
+		data() {
+			return {
+				src: 'https://cdn.uviewui.com/uview/album/1.jpg',
+				fileLists:[{
+					url:"https://cdn.uviewui.com/uview/album/1.txt"
+				},{
+					url:"https://cdn.uviewui.com/uview/album/1.pdf",
+				},
+				{
+					url: 'https://cdn.uviewui.com/uview/album/1.jpg',
+				},
+				{
+					url: 'https://cdn.uviewui.com/uview/album/1.jpg',
+				},{
+					url: 'https://cdn.uviewui.com/uview/album/1.jpg',
+				}],
+				fileList:[],
+				imgList:[]
+				// isoffice: false,
+				// isleader: false,
+				// isinfo: false
+			}
+		},
+		props: {
+			isoffice: {
+				type: Boolean,
+				default: false
+			},
+			isleader: {
+				type: Boolean,
+				default: false
+			},
+			isinfo: {
+				type: Boolean,
+				default: false
+			},
+		},
+	}
+</script>
+
+<style>
+	.card_main {
+		width: 100%;
+		background-color: #fefefe;
+	}
+
+	.card_banner {
+		width: 100%;
+		height: 60px;
+		background-color: #36a7f3;
+	}
+
+	.card_info {
+		width: 96%;
+		/* height: 80vh; */
+		margin: -40px 2% 0;
+		background-color: #fefefe;
+		border-radius: 15px;
+		text-align: center;
+	}
+
+	.card_info_title {
+		font-size: 16px;
+		font-weight: 700;
+		padding-top: 10px;
+		color: #36a7f3;
+	}
+
+	.card_table {
+		padding: 20px 20px;
+		font-size: 12px;
+	}
+
+	.card_row {
+		line-height: 30px;
+		border: 1px solid;
+		word-wrap: break-word;
+	}
+	.card_row_border {
+		border-top: none;
+	}
+	.card_col {
+		border-right: 1px solid;
+	}
+
+	.info_abstract {
+		line-height: 16px;
+		word-wrap: break-word;
+		border-left: 1px solid;
+	}
+	.info_abstract_v {
+		margin: 18px;
+	}
+	.vertical-text {
+		writing-mode: vertical-rl;
+		/* 文字垂直排列,从右向左 */
+		/* 或者使用vertical-lr; 从左向右 */
+	}
+
+	.card_other {
+		text-align: left;
+	}
+</style>

+ 32 - 0
jp-mobile/pages/fileTransmit/fileInfo.vue

@@ -0,0 +1,32 @@
+<template>
+	<view class="info_page">
+		<fileCard :isinfo="true"></fileCard>
+		<view class="info_main">
+			<u-steps current="0" direction="column" inactiveColor="#36a7f3" activeColor="#5fdf50">
+					<u-steps-item title="办公室拟办" desc="名字 - 2024-3-21 00:00">
+					</u-steps-item>
+					<u-steps-item title="领导审批" desc="名字 - 2024-3-21 00:00" ></u-steps-item>
+					<u-steps-item title="承办情况" ></u-steps-item>
+				</u-steps>
+		</view>
+	</view>
+</template>
+
+<script>
+	import fileCard from "./fileCard.vue"
+	export default{
+		components:{
+			fileCard,
+		}
+	}
+</script>
+
+<style>
+	.info_page {
+		width: 100%;
+		background-color: #fefefe;
+	}
+	.info_main {
+		margin: 20px;
+	}
+</style>

+ 113 - 0
jp-mobile/pages/fileTransmit/fileTransmitList.vue

@@ -0,0 +1,113 @@
+<template>
+	<view class="file_list_page">
+		<view class="list_search card_banner flex">
+			<uni-data-select class="list_search_select" v-model="value" :localdata="range" @change="change"
+				placeholder="发文部门"></uni-data-select>
+			<uni-datetime-picker class="list_search_date" v-model="time" type="daterange" @maskClick="maskClick" />
+			<u-icon class="list_search_icon" name="search" color="#fff" size="28"></u-icon>
+		</view>
+		<view class="list_content" >
+			<u-cell-group>
+				<u-cell v-for="item in dataList" >
+					<view slot="title" >
+						<view class="text-bold text-black">
+							<view class="ellipsis-description">
+								{{item.contentSummary}}
+							</view>
+						</view>
+					</view>
+					<view slot="value">
+						<view class="text-grey text-sm  list_label margin-top">
+							{{item.receivingTime}}
+						</view>
+					</view>
+					<view slot="label">
+						<view class="text-grey text-sm margin-top">
+							{{item.sendingAgency}}
+						</view>
+					</view>
+				</u-cell>
+			</u-cell-group>
+		</view>
+	</view>
+</template>
+
+<script>
+		import gwCirculationCard2Service from '@/api/circulation/gwCirculationCard2.js'
+	export default {
+		onLoad(option) {
+			if(option){
+				this.type = option.type
+				gwCirculationCard2Service.list({
+					
+				}).then(data =>{
+					console.log("list=============",data);
+					this.dataList = data.records
+
+				})
+			}
+		},
+		data() {
+			return {
+				type:"",
+				time:"",
+				value:"",
+				range: [{
+						value: 0,
+						text: "篮球"
+					},
+					{
+						value: 1,
+						text: "足球"
+					},
+					{
+						value: 2,
+						text: "游泳"
+					},
+				],
+				dataList: [],
+				tablePage: {
+					pages: 0,
+					currentPage: 0,
+					pageSize: 10,
+					orders: [{ column: "a.create_time", asc: false }],
+				},
+				loading: false,
+			}
+		},
+		methods:{
+			
+		}
+
+	}
+</script>
+
+<style>
+	.card_banner {
+		width: 100%;
+		height: 60px;
+		background-color: #36a7f3;
+	}
+
+	.list_search_icon {
+		line-height: 60px;
+	}
+
+	.list_search_select {
+		width: 200px;
+		background-color: #fff;
+		height: 30px;
+		border-radius: 10px;
+		margin: 15px 5px 0;
+	}
+
+	.list_search_date {
+		margin: 8px 5px 0;
+	}
+	.list_content {
+		background-color: #fff;
+	}
+	.list_label {
+		margin-top: 33px;
+	}
+</style>

+ 16 - 0
jp-mobile/pages/fileTransmit/statistics.vue

@@ -0,0 +1,16 @@
+<template>
+	<office-user-select></office-user-select>
+</template>
+
+<script>
+	import officeUserSelect from "@/components/office-user-select/office-user-select.vue"
+	export default{
+		components:{
+			officeUserSelect
+		},
+		
+	}
+</script>
+
+<style>
+</style>

+ 6 - 6
jp-mobile/pages/index/index.vue

@@ -1,9 +1,9 @@
 <template>
 	<view>
 		<addressbook v-if="PageCur=='addressbook'"></addressbook>
-		<message v-if="PageCur=='message'"></message>
+		<!-- <message v-if="PageCur=='message'"></message> -->
 		<workbench v-if="PageCur=='workbench'"></workbench>
-		<apps v-if="PageCur=='apps'"></apps>
+		<!-- <apps v-if="PageCur=='apps'"></apps> -->
 		<person v-if="PageCur=='my'"></person>
 		<view class="cu-bar tabbar bg-white shadow foot">
 			<view class="action" @click="NavChange" data-cur="addressbook">
@@ -12,25 +12,25 @@
 					<text>通讯录</text>
 				</view>
 			</view>
-			<view class="action" @click="NavChange" data-cur="message">
+			<!-- <view class="action" @click="NavChange" data-cur="message">
 				<view :class="PageCur=='message'?'text-blue':'text-gray'">
 					<text class="lg" :class="PageCur=='message'?'cuIcon-messagefill':'cuIcon-message'">
 						<text class='cu-tag badge'>0</text>
 					</text>
 					<text>消息</text>
 				</view>
-			</view>
+			</view> -->
 			<view class="action text-gray add-action"  @click="NavChange" data-cur="workbench">
 				<button class="cu-btn  shadow" :class="PageCur=='workbench'?'cuIcon-homefill bg-blue':'cuIcon-home bg-grey'"></button>
 				工作台
 			</view>
-			
+			<!-- 
 			<view class="action" @click="NavChange" data-cur="apps">
 				<view :class="PageCur=='apps'?'text-blue':'text-gray'">
 					<text class="lg" :class="PageCur=='apps'?'cuIcon-circlefill':'cuIcon-circle'"></text>
 					<text>应用</text>
 				</view>
-			</view>
+			</view> -->
 			
 			<view class="action" @click="NavChange" data-cur="my">
 				<view :class="PageCur=='my'?'text-blue':'text-gray'">

+ 47 - 28
jp-mobile/pages/workbench/workbench.vue

@@ -1,7 +1,7 @@
 <template>
 	<view>
 		<cu-custom bgColor="bg-blue">
-			<block slot="content"> 工作台</block>
+			<block slot="content">文件传阅</block>
 		</cu-custom>
 		<swiper class="screen-swiper square-dot bg-blue"  :indicator-dots="true" :circular="true"
 		 :autoplay="true" interval="2000" duration="500">
@@ -11,37 +11,55 @@
 			</swiper-item>
 		</swiper>
 		<view class="cu-list grid col-4 no-border fixed">
-			<view @tap="toTodoList" class="circle-button-box">
-				<view class="cuIcon-time text-blue circle-button font-size-35"></view>
-				<text>待办事项</text>
+			<view class="circle-button-box">
+				<view class="text-primary text_font_size">26</view>
+				<text>总数</text>
 			</view>
-			<view @tap="toHistoryList" class="circle-button-box">
-				<view class="cuIcon-roundcheck  text-blue circle-button font-size-35"></view>
-				<text>已办事项</text>
+			<view class="circle-button-box">
+				<view class="text-danger text_font_size">5</view>
+				<text>待办</text>
 			</view>
-			<view @tap="toApplyList" class="circle-button-box">
-				<view   class="cuIcon-peoplelist text-blue circle-button font-size-35"></view>
-				<text>我发起的</text>
+			<view class="circle-button-box">
+				<view class="text-success text_font_size">26</view>
+				<text>已办</text>
 			</view>
-			<view @tap="toFlowCopyList" class="circle-button-box">
-				<view class="cuIcon-copy  text-blue circle-button font-size-35"></view>
-				<text>抄送给我</text>
+			<view class="circle-button-box">
+				<view class="text-warning text_font_size">26</view>
+				<text>归档</text>
 			</view>
 		</view>
 		<scroll-view scroll-y class="page">
-			<template v-for="key in processMap.keys()">
 				<view class="cu-bar bg-white solid-bottom margin-top">
 					<view class="action">
-						<text class=" text-orange font-b">{{key}}</text>
+						<text class=" text-orange font-b">快捷入口</text>
 					</view>
 				</view>
 				<view class="cu-list grid col-4 no-border">
-				<view class="circle-button-box" @click="start(act)" v-for="(act, index) in processMap.get(key)" :key="index">
-					<view class="cuIcon-calendar bg-blue text-white circle-button font-size-35"></view>
-					<text class="ellipsis-description">{{act.name}}</text>
+				<view @tap="add" class="circle-button-box">
+					<view ><u--image src="/static/index/icon4.png" width="40px" height="40px"></u--image></view>
+					<text>新增</text>
+				</view>
+				<view @tap="toList(1)" class="circle-button-box">
+					<view ><u--image src="/static/index/icon1.png" width="40px" height="40px"></u--image></view>
+					<text>待办</text>
+				</view>
+				<view @tap="toList(4)" class="circle-button-box">
+					<view ><u--image src="/static/index/icon5.png" width="40px" height="40px"></u--image></view>
+					<text>已办</text>
+				</view>
+				<view @tap="toList(3)" class="circle-button-box">
+					<view ><u--image src="/static/index/icon2.png" width="40px" height="40px"></u--image></view>
+					<text>已归档</text>
+				</view>
+				<view @tap="" class="circle-button-box">
+					<view ><u--image src="/static/index/icon3.png" width="40px" height="40px"></u--image></view>
+					<text>通讯录</text>
+				</view>
+				<view @tap="toApplyList" class="circle-button-box">
+					<view ><u--image src="/static/index/icon6.png" width="40px" height="40px"></u--image></view>
+					<text>公文统计</text>
 				</view>
 				</view>
-			</template>
 			
 			<u-gap height="80" bgColor="#fff"></u-gap>
 		</scroll-view>
@@ -131,22 +149,22 @@
 			 ...mapActions(['refreshUserInfo']),
 			toApplyList (mail) {
 				uni.navigateTo({
-				   url: '/pages/workbench/task/ApplyList'
+				   url: '/pages/fileTransmit/statistics'
 				})
 			},
-			toTodoList (mail) {
+			add (mail) {
 				uni.navigateTo({
-				    url: '/pages/workbench/task/TodoList'
+				    url: '/pages/fileTransmit/addFileTransmit'
 				})
 			},
-			toHistoryList (mail) {
+			examine (mail) {
 				uni.navigateTo({
-				    url: '/pages/workbench/task/HistoryList'
+				    url: '/pages/fileTransmit/examineFile'
 				})
 			},
-			toFlowCopyList (mail) {
+			toList (type) {
 				uni.navigateTo({
-				    url: '/pages/workbench/task/FlowCopyList'
+				    url: '/pages/fileTransmit/fileTransmitList?type='+type
 				})
 			},
 			start (row) {
@@ -188,8 +206,9 @@
       width: 1.6em;
       text-align: center;
   }
-  .font-size-35{
-	 font-size: 35px!important;
+  .text_font_size{
+	 font-size: 28px!important;
+	 margin-bottom: 10px;
   }
   .circle-button{
 	 width: 44px;

+ 1 - 0
jp-mobile/static/css/main.css

@@ -13,6 +13,7 @@
 body {
 	font-size: 28upx;
 	color: #333333;
+	background-color: #eee;
 	font-family: Helvetica Neue, Helvetica, sans-serif;
 }
 

BIN
jp-mobile/static/index/icon1.png


BIN
jp-mobile/static/index/icon2.png


BIN
jp-mobile/static/index/icon3.png


BIN
jp-mobile/static/index/icon4.png


BIN
jp-mobile/static/index/icon5.png


BIN
jp-mobile/static/index/icon6.png


BIN
jp-mobile/static/other/color_black.png


BIN
jp-mobile/static/other/color_black_selected.png


BIN
jp-mobile/static/other/color_red.png


BIN
jp-mobile/static/other/color_red_selected.png


BIN
jp-mobile/static/other/signs.png


+ 37 - 0
jp-mobile/uni_modules/uni-data-select/changelog.md

@@ -0,0 +1,37 @@
+## 1.0.7(2024-01-20)
+- 修复 长文本回显超过容器的bug,超过容器部分显示省略号
+## 1.0.6(2023-04-12)
+- 修复 微信小程序点击时会改变背景颜色的 bug
+## 1.0.5(2023-02-03)
+- 修复 禁用时会显示清空按钮
+## 1.0.4(2023-02-02)
+- 优化 查询条件短期内多次变更只查询最后一次变更后的结果
+- 调整 内部缓存键名调整为 uni-data-select-lastSelectedValue
+## 1.0.3(2023-01-16)
+- 修复 不关联服务空间报错的问题
+## 1.0.2(2023-01-14)
+- 新增  属性 `format` 可用于格式化显示选项内容
+## 1.0.1(2022-12-06)
+- 修复  当where变化时,数据不会自动更新的问题
+## 0.1.9(2022-09-05)
+- 修复 微信小程序下拉框出现后选择会点击到蒙板后面的输入框
+## 0.1.8(2022-08-29)
+- 修复 点击的位置不准确
+## 0.1.7(2022-08-12)
+- 新增 支持 disabled 属性
+## 0.1.6(2022-07-06)
+- 修复 pc端宽度异常的bug
+## 0.1.5
+- 修复 pc端宽度异常的bug
+## 0.1.4(2022-07-05)
+- 优化 显示样式
+## 0.1.3(2022-06-02)
+- 修复 localdata 赋值不生效的 bug
+- 新增 支持  uni.scss 修改颜色
+- 新增 支持选项禁用(数据选项设置 disabled: true 即禁用)
+## 0.1.2(2022-05-08)
+- 修复 当 value 为 0 时选择不生效的 bug
+## 0.1.1(2022-05-07)
+- 新增 记住上次的选项(仅 collection 存在时有效)
+## 0.1.0(2022-04-22)
+- 初始化

+ 527 - 0
jp-mobile/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue

@@ -0,0 +1,527 @@
+<template>
+	<view class="uni-stat__select">
+		<span v-if="label" class="uni-label-text hide-on-phone">{{label + ':'}}</span>
+		<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
+			<view class="uni-select" :class="{'uni-select--disabled':disabled}">
+				<view class="uni-select__input-box" @click="toggleSelector">
+					<view v-if="current" class="uni-select__input-text">{{textShow}}</view>
+					<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
+					<view v-if="current && clear && !disabled" @click.stop="clearVal" >
+						<uni-icons type="clear" color="#c0c4cc" size="24"/>
+					</view>
+					<view v-else>
+						<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
+					</view>
+				</view>
+				<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
+				<view class="uni-select__selector" v-if="showSelector">
+					<view class="uni-popper__arrow"></view>
+					<scroll-view scroll-y="true" class="uni-select__selector-scroll">
+						<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
+							<text>{{emptyTips}}</text>
+						</view>
+						<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" :key="index"
+							@click="change(item)">
+							<text :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
+						</view>
+					</scroll-view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * DataChecklist 数据选择器
+	 * @description 通过数据渲染的下拉框组件
+	 * @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
+	 * @property {String} value 默认值
+	 * @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
+	 * @property {Boolean} clear 是否可以清空已选项
+	 * @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
+	 * @property {String} label 左侧标题
+	 * @property {String} placeholder 输入框的提示文字
+	 * @property {Boolean} disabled 是否禁用
+	 * @event {Function} change  选中发生变化触发
+	 */
+
+	export default {
+		name: "uni-data-select",
+		mixins: [uniCloud.mixinDatacom || {}],
+		props: {
+			localdata: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			value: {
+				type: [String, Number],
+				default: ''
+			},
+			modelValue: {
+				type: [String, Number],
+				default: ''
+			},
+			label: {
+				type: String,
+				default: ''
+			},
+			placeholder: {
+				type: String,
+				default: '请选择'
+			},
+			emptyTips: {
+				type: String,
+				default: '无选项'
+			},
+			clear: {
+				type: Boolean,
+				default: true
+			},
+			defItem: {
+				type: Number,
+				default: 0
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+			// 格式化输出 用法 field="_id as value, version as text, uni_platform as label" format="{label} - {text}"
+			format: {
+				type: String,
+				default: ''
+			},
+		},
+		data() {
+			return {
+				showSelector: false,
+				current: '',
+				mixinDatacomResData: [],
+				apps: [],
+				channels: [],
+				cacheKey: "uni-data-select-lastSelectedValue",
+			};
+		},
+		created() {
+			this.debounceGet = this.debounce(() => {
+				this.query();
+			}, 300);
+			if (this.collection && !this.localdata.length) {
+				this.debounceGet();
+			}
+		},
+		computed: {
+			typePlaceholder() {
+				const text = {
+					'opendb-stat-app-versions': '版本',
+					'opendb-app-channels': '渠道',
+					'opendb-app-list': '应用'
+				}
+				const common = this.placeholder
+				const placeholder = text[this.collection]
+				return placeholder ?
+					common + placeholder :
+					common
+			},
+			valueCom(){
+				// #ifdef VUE3
+				return this.modelValue;
+				// #endif
+				// #ifndef VUE3
+				return this.value;
+				// #endif
+			},
+			textShow(){
+				// 长文本显示
+				let text = this.current;
+				if (text.length > 10) {
+					return text.slice(0, 25) + '...';
+				}
+				return text;
+			}
+		},
+
+		watch: {
+			localdata: {
+				immediate: true,
+				handler(val, old) {
+					if (Array.isArray(val) && old !== val) {
+						this.mixinDatacomResData = val
+					}
+				}
+			},
+			valueCom(val, old) {
+				this.initDefVal()
+			},
+			mixinDatacomResData: {
+				immediate: true,
+				handler(val) {
+					if (val.length) {
+						this.initDefVal()
+					}
+				}
+			},
+
+		},
+		methods: {
+			debounce(fn, time = 100){
+				let timer = null
+				return function(...args) {
+					if (timer) clearTimeout(timer)
+					timer = setTimeout(() => {
+						fn.apply(this, args)
+					}, time)
+				}
+			},
+			// 执行数据库查询
+			query(){
+				this.mixinDatacomEasyGet();
+			},
+			// 监听查询条件变更事件
+			onMixinDatacomPropsChange(){
+				if (this.collection) {
+					this.debounceGet();
+				}
+			},
+			initDefVal() {
+				let defValue = ''
+				if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
+					defValue = this.valueCom
+				} else {
+					let strogeValue
+					if (this.collection) {
+						strogeValue = this.getCache()
+					}
+					if (strogeValue || strogeValue === 0) {
+						defValue = strogeValue
+					} else {
+						let defItem = ''
+						if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
+							defItem = this.mixinDatacomResData[this.defItem - 1].value
+						}
+						defValue = defItem
+					}
+          if (defValue || defValue === 0) {
+					  this.emit(defValue)
+          }
+				}
+				const def = this.mixinDatacomResData.find(item => item.value === defValue)
+				this.current = def ? this.formatItemName(def) : ''
+			},
+
+			/**
+			 * @param {[String, Number]} value
+			 * 判断用户给的 value 是否同时为禁用状态
+			 */
+			isDisabled(value) {
+				let isDisabled = false;
+
+				this.mixinDatacomResData.forEach(item => {
+					if (item.value === value) {
+						isDisabled = item.disable
+					}
+				})
+
+				return isDisabled;
+			},
+
+			clearVal() {
+				this.emit('')
+				if (this.collection) {
+					this.removeCache()
+				}
+			},
+			change(item) {
+				if (!item.disable) {
+					this.showSelector = false
+					this.current = this.formatItemName(item)
+					this.emit(item.value)
+				}
+			},
+			emit(val) {
+				this.$emit('input', val)
+				this.$emit('update:modelValue', val)
+				this.$emit('change', val)
+				if (this.collection) {
+					this.setCache(val);
+				}
+			},
+			toggleSelector() {
+				if (this.disabled) {
+					return
+				}
+
+				this.showSelector = !this.showSelector
+			},
+			formatItemName(item) {
+				let {
+					text,
+					value,
+					channel_code
+				} = item
+				channel_code = channel_code ? `(${channel_code})` : ''
+
+				if (this.format) {
+					// 格式化输出
+					let str = "";
+					str = this.format;
+					for (let key in item) {
+						str = str.replace(new RegExp(`{${key}}`,"g"),item[key]);
+					}
+					return str;
+				} else {
+					return this.collection.indexOf('app-list') > 0 ?
+						`${text}(${value})` :
+						(
+							text ?
+							text :
+							`未命名${channel_code}`
+						)
+				}
+			},
+			// 获取当前加载的数据
+			getLoadData(){
+				return this.mixinDatacomResData;
+			},
+			// 获取当前缓存key
+			getCurrentCacheKey(){
+				return this.collection;
+			},
+			// 获取缓存
+			getCache(name=this.getCurrentCacheKey()){
+				let cacheData = uni.getStorageSync(this.cacheKey) || {};
+				return cacheData[name];
+			},
+			// 设置缓存
+			setCache(value, name=this.getCurrentCacheKey()){
+				let cacheData = uni.getStorageSync(this.cacheKey) || {};
+				cacheData[name] = value;
+				uni.setStorageSync(this.cacheKey, cacheData);
+			},
+			// 删除缓存
+			removeCache(name=this.getCurrentCacheKey()){
+				let cacheData = uni.getStorageSync(this.cacheKey) || {};
+				delete cacheData[name];
+				uni.setStorageSync(this.cacheKey, cacheData);
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	$uni-base-color: #6a6a6a !default;
+	$uni-main-color: #333 !default;
+	$uni-secondary-color: #909399 !default;
+	$uni-border-3: #e5e5e5;
+
+
+	/* #ifndef APP-NVUE */
+	@media screen and (max-width: 500px) {
+		.hide-on-phone {
+			display: none;
+		}
+	}
+
+	/* #endif */
+	.uni-stat__select {
+		display: flex;
+		align-items: center;
+		// padding: 15px;
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+		width: 100%;
+		flex: 1;
+		box-sizing: border-box;
+	}
+
+	.uni-stat-box {
+		width: 100%;
+		flex: 1;
+	}
+
+	.uni-stat__actived {
+		width: 100%;
+		flex: 1;
+		// outline: 1px solid #2979ff;
+	}
+
+	.uni-label-text {
+		font-size: 14px;
+		font-weight: bold;
+		color: $uni-base-color;
+		margin: auto 0;
+		margin-right: 5px;
+	}
+
+	.uni-select {
+		font-size: 14px;
+		// border: 1px solid $uni-border-3;
+		box-sizing: border-box;
+		border-radius: 4px;
+		padding: 0 5px;
+		padding-left: 10px;
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		user-select: none;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		// border-bottom: solid 1px $uni-border-3;
+		width: 100%;
+		flex: 1;
+		height: 35px;
+
+		&--disabled {
+			background-color: #f5f7fa;
+			cursor: not-allowed;
+		}
+	}
+
+	.uni-select__label {
+		font-size: 16px;
+		// line-height: 22px;
+		height: 35px;
+		padding-right: 10px;
+		color: $uni-secondary-color;
+	}
+
+	.uni-select__input-box {
+		height: 35px;
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex: 1;
+		flex-direction: row;
+		align-items: center;
+	}
+
+	.uni-select__input {
+		flex: 1;
+		font-size: 14px;
+		height: 22px;
+		line-height: 22px;
+	}
+
+	.uni-select__input-plac {
+		font-size: 14px;
+		color: $uni-secondary-color;
+	}
+
+	.uni-select__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-select__selector-scroll {
+		/* #ifndef APP-NVUE */
+		max-height: 200px;
+		box-sizing: border-box;
+		/* #endif */
+	}
+
+	/* #ifdef H5 */
+	@media (min-width: 768px) {
+		.uni-select__selector-scroll {
+			max-height: 600px;
+		}
+	}
+	/* #endif */
+
+	.uni-select__selector-empty,
+	.uni-select__selector-item {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		cursor: pointer;
+		/* #endif */
+		line-height: 35px;
+		font-size: 14px;
+		text-align: center;
+		/* border-bottom: solid 1px $uni-border-3; */
+		padding: 0px 10px;
+	}
+
+	.uni-select__selector-item:hover {
+		background-color: #f9f9f9;
+	}
+
+	.uni-select__selector-empty:last-child,
+	.uni-select__selector-item:last-child {
+		/* #ifndef APP-NVUE */
+		border-bottom: none;
+		/* #endif */
+	}
+
+	.uni-select__selector__disabled {
+		opacity: 0.4;
+		cursor: default;
+	}
+
+	/* 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-select__input-text {
+		// width: 280px;
+		width: 100%;
+		color: $uni-main-color;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+		-o-text-overflow: ellipsis;
+		overflow: hidden;
+	}
+
+	.uni-select__input-placeholder {
+		color: $uni-base-color;
+		font-size: 12px;
+	}
+
+	.uni-select--mask {
+		position: fixed;
+		top: 0;
+		bottom: 0;
+		right: 0;
+		left: 0;
+		z-index: 2;
+	}
+</style>

+ 85 - 0
jp-mobile/uni_modules/uni-data-select/package.json

@@ -0,0 +1,85 @@
+{
+  "id": "uni-data-select",
+  "displayName": "uni-data-select 下拉框选择器",
+  "version": "1.0.7",
+  "description": "通过数据驱动的下拉框选择器",
+  "keywords": [
+    "uni-ui",
+    "select",
+    "uni-data-select",
+    "下拉框",
+    "下拉选"
+],
+  "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"],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "u",
+          "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"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 8 - 0
jp-mobile/uni_modules/uni-data-select/readme.md

@@ -0,0 +1,8 @@
+## DataSelect 下拉框选择器
+> **组件名:uni-data-select**
+> 代码块: `uDataSelect`
+
+当选项过多时,使用下拉菜单展示并选择内容
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-select)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 2 - 0
jp-mobile/uni_modules/uni-section/changelog.md

@@ -0,0 +1,2 @@
+## 0.0.1(2022-07-22)
+- 初始化

+ 167 - 0
jp-mobile/uni_modules/uni-section/components/uni-section/uni-section.vue

@@ -0,0 +1,167 @@
+<template>
+	<view class="uni-section">
+		<view class="uni-section-header" @click="onClick">
+				<view class="uni-section-header__decoration" v-if="type" :class="type" />
+        <slot v-else name="decoration"></slot>
+
+        <view class="uni-section-header__content">
+          <text :style="{'font-size':titleFontSize,'color':titleColor}" class="uni-section__content-title" :class="{'distraction':!subTitle}">{{ title }}</text>
+          <text v-if="subTitle" :style="{'font-size':subTitleFontSize,'color':subTitleColor}" class="uni-section-header__content-sub">{{ subTitle }}</text>
+        </view>
+
+        <view class="uni-section-header__slot-right">
+          <slot name="right"></slot>
+        </view>
+		</view>
+
+		<view class="uni-section-content" :style="{padding: _padding}">
+			<slot />
+		</view>
+	</view>
+</template>
+
+<script>
+
+	/**
+	 * Section 标题栏
+	 * @description 标题栏
+	 * @property {String} type = [line|circle|square] 标题装饰类型
+	 * 	@value line 竖线
+	 * 	@value circle 圆形
+	 * 	@value square 正方形
+	 * @property {String} title 主标题
+	 * @property {String} titleFontSize 主标题字体大小
+	 * @property {String} titleColor 主标题字体颜色
+	 * @property {String} subTitle 副标题
+	 * @property {String} subTitleFontSize 副标题字体大小
+	 * @property {String} subTitleColor 副标题字体颜色
+	 * @property {String} padding 默认插槽 padding
+	 */
+
+	export default {
+		name: 'UniSection',
+    emits:['click'],
+		props: {
+			type: {
+				type: String,
+				default: ''
+			},
+			title: {
+				type: String,
+				required: true,
+				default: ''
+			},
+      titleFontSize: {
+        type: String,
+        default: '14px'
+      },
+			titleColor:{
+				type: String,
+				default: '#333'
+			},
+			subTitle: {
+				type: String,
+				default: ''
+			},
+      subTitleFontSize: {
+        type: String,
+        default: '12px'
+      },
+      subTitleColor: {
+        type: String,
+        default: '#999'
+      },
+			padding: {
+				type: [Boolean, String],
+				default: false
+			}
+		},
+    computed:{
+      _padding(){
+        if(typeof this.padding === 'string'){
+          return this.padding
+        }
+
+        return this.padding?'10px':''
+      }
+    },
+		watch: {
+			title(newVal) {
+				if (uni.report && newVal !== '') {
+					uni.report('title', newVal)
+				}
+			}
+		},
+    methods: {
+			onClick() {
+				this.$emit('click')
+			}
+		}
+	}
+</script>
+<style lang="scss" >
+	$uni-primary: #2979ff !default;
+
+	.uni-section {
+		background-color: #fff;
+    .uni-section-header {
+      position: relative;
+      /* #ifndef APP-NVUE */
+      display: flex;
+      /* #endif */
+      flex-direction: row;
+      align-items: center;
+      padding: 12px 10px;
+      font-weight: normal;
+
+      &__decoration{
+        margin-right: 6px;
+        background-color: $uni-primary;
+        &.line {
+          width: 4px;
+          height: 12px;
+          border-radius: 10px;
+        }
+
+        &.circle {
+          width: 8px;
+          height: 8px;
+          border-top-right-radius: 50px;
+          border-top-left-radius: 50px;
+          border-bottom-left-radius: 50px;
+          border-bottom-right-radius: 50px;
+        }
+
+        &.square {
+          width: 8px;
+          height: 8px;
+        }
+      }
+
+      &__content {
+        /* #ifndef APP-NVUE */
+        display: flex;
+        /* #endif */
+        flex-direction: column;
+        flex: 1;
+        color: #333;
+
+        .distraction {
+          flex-direction: row;
+          align-items: center;
+        }
+        &-sub {
+          margin-top: 2px;
+        }
+      }
+
+      &__slot-right{
+        font-size: 14px;
+      }
+    }
+
+    .uni-section-content{
+      font-size: 14px;
+    }
+	}
+</style>

+ 87 - 0
jp-mobile/uni_modules/uni-section/package.json

@@ -0,0 +1,87 @@
+{
+  "id": "uni-section",
+  "displayName": "uni-section 标题栏",
+  "version": "0.0.1",
+  "description": "标题栏组件",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "标题栏"
+],
+  "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"
+        }
+      }
+    }
+  }
+}

+ 8 - 0
jp-mobile/uni_modules/uni-section/readme.md

@@ -0,0 +1,8 @@
+## Section 标题栏
+> **组件名:uni-section**
+> 代码块: `uSection`
+
+uni-section 组件主要用于文章、列表详情等标题展示
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-section)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839

+ 3 - 3
jp-ui/src/App.vue

@@ -7,9 +7,9 @@
 <script>
 import colorTool from "@/utils/color";
 import languageService from "@/api/sys/languageService";
-import zh from "element-plus/lib/locale/lang/zh-cn";
-import en from "element-plus/lib/locale/lang/en";
-import ja from "element-plus/lib/locale/lang/ja";
+import zh from "element-plus/es/locale/lang/zh-cn";
+import en from "element-plus/es/locale/lang/en";
+import ja from "element-plus/es/locale/lang/ja";
 export default {
 	name: "App",
 	data: () => ({

+ 1 - 1
jp-ui/src/main.js

@@ -2,7 +2,7 @@ import { createApp } from "vue";
 import ElementPlus from "element-plus";
 import "element-plus/dist/index.css";
 import "element-plus/theme-chalk/display.css";
-import locale from "element-plus/lib/locale/lang/zh-cn";
+import locale from "element-plus/es/locale/lang/zh-cn";
 import moment from "moment";
 
 import VXETable from "vxe-table";