Преглед изворни кода

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	jp-console/jeeplus-module/ly/src/main/java/com/jeeplus/question/mapper/DzfQuestionMapper.java
yin_yu820 пре 2 недеља
родитељ
комит
4f090c57d0

+ 21 - 2
jp-console/jeeplus-module/ly/src/main/java/com/jeeplus/question/controller/DzfQuestionController.java

@@ -4,8 +4,7 @@
 package com.jeeplus.question.controller;
 
 import java.io.IOException;
-import java.util.List;
-import java.util.UUID;
+import java.util.*;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import com.google.common.collect.Lists;
@@ -213,6 +212,26 @@ public class DzfQuestionController {
 		return ResponseEntity.ok( "删除问题诉求成功" );
 	}
 
+	/**
+	 * 进度统计
+	 */
+
+	@ApiLog("获取进度统计数据")
+	@ApiOperation(value = "获取进度统计数据")
+	@GetMapping("getProgressStatistics")
+	public ResponseEntity<HashMap<Object,String>> getProgressStatistics(String start, String end) {
+		if (start.equals("")){
+			Calendar calendar = Calendar.getInstance();
+			int year = calendar.get(Calendar.YEAR);
+			int month = calendar.get(Calendar.MONTH) + 1; // 月份从0开始计数,所以要加1
+			int day = calendar.get(Calendar.DAY_OF_MONTH);
+			end = year+"-"+ month + "-" + day;
+			start =year+"-"+month+"-01";
+		}
+		HashMap<Object,String> result = dzfQuestionService.getProgressStatistics(start,end);
+		return ResponseEntity.ok ( result );
+	}
+
 	/**
      * 导出问题诉求数据
      *

+ 6 - 0
jp-console/jeeplus-module/ly/src/main/java/com/jeeplus/question/mapper/DzfQuestionMapper.java

@@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.jeeplus.question.service.dto.DzfQuestionDTO;
 import com.jeeplus.question.domain.DzfQuestion;
 
+import java.util.HashMap;
+
 /**
  * 问题诉求MAPPER接口
  * @author 尹宇
@@ -34,4 +36,8 @@ public interface DzfQuestionMapper extends BaseMapper<DzfQuestion> {
      */
     IPage <DzfQuestionDTO> findList(Page <DzfQuestionDTO> page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper);
     IPage <DzfQuestionDTO> findList2(Page <DzfQuestionDTO> page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper);
+
+    HashMap<Object, Object> getProgressMonth(@Param("start")String start,@Param("end")String end);
+
+    HashMap<Object, Object> getProgressYear(@Param("start")String start,@Param("end")String end);
 }

+ 12 - 0
jp-console/jeeplus-module/ly/src/main/java/com/jeeplus/question/mapper/xml/DzfQuestionMapper.xml

@@ -69,4 +69,16 @@
 		group by a.id
 	</select>
 
+	<select id="getProgressMonth" resultType="Map"  parameterType="String">
+		SELECT COUNT(*) allque, COUNT(IF(states != 3,1,NULL )) AS unfinish
+		FROM dzf_question WHERE del_flag = 0
+		AND DATE_FORMAT(create_date, '%Y-%m-%d') >= #{start} AND DATE_FORMAT(create_date, '%Y-%m-%d') &lt;= #{end};
+	</select>
+
+	<select id="getProgressYear" resultType="Map" parameterType="String">
+		SELECT COUNT(*) allque, COUNT(IF(states = 3,1,NULL )) AS finish
+		FROM dzf_question WHERE del_flag = 0
+		AND DATE_FORMAT(create_date,'%Y') = DATE_FORMAT(#{end},'%Y');
+	</select>
+
 </mapper>

+ 34 - 0
jp-console/jeeplus-module/ly/src/main/java/com/jeeplus/question/service/DzfQuestionService.java

@@ -19,6 +19,9 @@ import com.jeeplus.question.domain.DzfQuestion;
 import com.jeeplus.question.domain.DzfQuestionDetil;
 import com.jeeplus.question.mapper.DzfQuestionMapper;
 
+import java.math.BigDecimal;
+import java.util.HashMap;
+
 /**
  * 问题诉求Service
  * @author 尹宇
@@ -90,4 +93,35 @@ public class DzfQuestionService extends ServiceImpl<DzfQuestionMapper, DzfQuesti
 		dzfQuestionDetilService.lambdaUpdate ().eq ( DzfQuestionDetil::getQidId, id ).remove ();
 	}
 
+    public HashMap<Object, String> getProgressStatistics(String start,String end) {
+		HashMap<Object, String> allNum = new HashMap<>();
+		// 月份
+		HashMap<Object, Object> monthNum = baseMapper.getProgressMonth(start,end);
+		// 计算占比
+		double unAcount =  0;
+		double unfinish = Double.valueOf(monthNum.get("unfinish").toString());
+		double monthallque = Double.valueOf(monthNum.get("allque").toString());
+		if(monthallque != 0){
+			unAcount = unfinish / monthallque * 100;
+		}
+		// 年份
+		HashMap<Object, Object> yearNum = baseMapper.getProgressYear(start,end);
+		// 计算占比
+		double finishAcount = 0 ;
+		double finish = Double.valueOf(yearNum.get("finish").toString());
+		double yearallque = Double.valueOf(yearNum.get("allque").toString());
+		if(yearallque!=0){
+			finishAcount = finish / yearallque * 100;
+		}
+		// 保存两位小数
+		BigDecimal bg = new BigDecimal(unAcount);
+		double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+		BigDecimal bg2 = new BigDecimal(finishAcount);
+		double f2 = bg2.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+		allNum.put("unfinish", String.valueOf(monthNum.get("unfinish")));
+		allNum.put("finish", String.valueOf(yearNum.get("finish")));
+		allNum.put("unAcount", String.valueOf(f1));
+		allNum.put("finishAcount", String.valueOf(f2));
+		return allNum;
+    }
 }

+ 75 - 0
jp-mobile/api/question/dzfQuestionService.js

@@ -0,0 +1,75 @@
+import request from "../../common/request"
+
+export default {
+	save: function(inputForm) {
+		return request({
+			url: '/question/dzfQuestion/save',
+			method: 'post',
+			data: inputForm
+		})
+	},
+
+	delete: function(ids) {
+		return request({
+			url: '/question/dzfQuestion/delete',
+			method: 'delete',
+			params: {
+				ids: ids
+			}
+		})
+	},
+
+	queryById: function(id) {
+		return request({
+			url: '/question/dzfQuestion/queryById',
+			method: 'get',
+			params: {
+				id: id
+			}
+		})
+	},
+
+	list: function(params) {
+		return request({
+			url: '/question/dzfQuestion/list',
+			method: 'get',
+			params: params
+		})
+	},
+
+	getProgressStatistics: function(start, end) {
+		return request({
+			url: '/question/dzfQuestion/getProgressStatistics',
+			method: 'get',
+			params: {
+				start: start,
+				end: end
+			}
+		})
+	},
+
+	exportTemplate: function() {
+		return request({
+			url: '/question/dzfQuestion/import/template',
+			method: 'get',
+			responseType: 'blob'
+		})
+	},
+
+	exportExcel: function(params) {
+		return request({
+			url: '/question/dzfQuestion/export',
+			method: 'get',
+			params: params,
+			responseType: 'blob'
+		})
+	},
+
+	importExcel: function(data) {
+		return request({
+			url: '/question/dzfQuestion/import',
+			method: 'post',
+			data: data
+		})
+	}
+}

+ 11 - 0
jp-mobile/pages.json

@@ -36,6 +36,10 @@
 			"path": "pages/policy/policyInfo",
 			"style": {}
 		},
+		{
+			"path": "pages/progress/progressStatistics",
+			"style": {}
+		},
 		{
 			"path": "pages/login/login",
 			"style": {
@@ -449,6 +453,13 @@
 			{
 				"navigationBarTitleText" : "园区信息展示"
 			}
+		},
+		{
+			"path" : "pages/progress/progressStatistics",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
 		}
     ],
 	"globalStyle": {

+ 180 - 0
jp-mobile/pages/progress/progressStatistics.vue

@@ -0,0 +1,180 @@
+<template>
+	<view style="background-color: #fff;height: 100vh;">
+		<uni-datetime-picker v-model="range" v-show="activeIndex == 0" type="daterange" @change="maskClick" />
+		<uni-datetime-picker v-model="year" v-show="activeIndex == 1" type="daterange" @change="maskClick" />
+		<view class="alarmList">
+			<view class="switchHead">
+				<view v-for="(item,index) in tabTitleData" class="boxList" :class="{activeCss:activeIndex==index}"
+					:key="index">
+					<text @click="clickTab(index)">{{item.name}}</text>
+				</view>
+			</view>
+			<view class="progress_list">
+				<uni-row :gutter="5">
+					<uni-col :span="12">
+						<view>
+							<uni-card margin="5px" shadow="0px 0px 3px 1px #36A7F3">
+								<view class="progress_section_1"></view><text>未办结问题数</text>
+								<view><text class="progress_num">{{unfinish}}</text>个</view>
+								<view class="progress_account">占比<text
+										style="color: red;margin-left: 5px;">{{unfinishAccount}}%</text></view>
+							</uni-card>
+						</view>
+					</uni-col>
+					<uni-col :span="12">
+						<view>
+							<uni-card margin="5px" shadow="0px 0px 3px 1px #36A7F3">
+								<view class="progress_section_2"></view><text>办结问题数</text>
+								<view><text class="progress_num">{{finish}}</text>个</view>
+								<view class="progress_account">占比<text
+										style="color: #36A7F3;margin-left: 5px;">{{finishAccount}}%</text></view>
+							</uni-card>
+						</view>
+					</uni-col>
+				</uni-row>
+			</view>
+		</view>
+	</view>
+
+</template>
+
+<script>
+	import dzfQuestionService from '@/api/question/dzfQuestionService.js'
+	export default {
+		data() {
+			return {
+				range: ['2021-02-1', '2021-3-28'],
+				year:['',''],
+				datetimerange: [],
+				start: Date.now() - 1000000000,
+				end: Date.now() + 1000000000,
+				activeIndex: '0',
+				tabTitleData: [{
+						name: '当月累计'
+					},
+					{
+						name: '当年累计'
+					}
+				],
+				finish: 0,
+				unfinish: 0,
+				finishAccount: 0,
+				unfinishAccount: 0
+			}
+		},
+		onShow() {
+			var date = new Date();
+			var year = date.getFullYear(); // 年份
+			var month = date.getMonth() + 1; // 月份,返回值为0-11,所以需要加1
+			var day = date.getDate(); // 日期
+
+			// 对月份和日期进行补零
+			month = month < 10 ? '0' + month : month.toString();
+			day = day < 10 ? '0' + day : day.toString();
+
+			var currentDate = year + '-' + month + '-' + day;
+			var start = year + '-' + month + '-01'
+			this.range[0] = start
+			this.range[1] = currentDate
+			this.year[0] = year + '-01-01'
+			this.year[1] = currentDate
+			this.getData(start,currentDate)
+		},
+		methods: {
+			clickTab(index) {
+				this.activeIndex = index;
+				var date = new Date();
+				var year = date.getFullYear(); // 年份
+				var month = date.getMonth() + 1; // 月份,返回值为0-11,所以需要加1
+				var day = date.getDate(); // 日期
+				
+				// 对月份和日期进行补零
+				month = month < 10 ? '0' + month : month.toString();
+				day = day < 10 ? '0' + day : day.toString();
+				var currentDate = year + '-' + month + '-' + day;
+				var start = year + '-' + month + '-01'
+				this.range[1] = currentDate
+				if(index == 1){
+					this.range[0] = year + '-01-01'
+					this.$forceUpdate();
+				}
+				this.getData(start,currentDate)
+			},
+			getData(start,end){
+				dzfQuestionService.getProgressStatistics(start,end).then(({data}) =>{
+					
+					this.finish = data.finish
+					this.unfinish = data.unfinish
+					this.finishAccount = data.finishAcount
+					this.unfinishAccount = data.unAcount
+					
+				})
+			},
+			maskClick(e){
+				this.getData(e[0],e[1]);
+			}
+			
+		}
+	}
+</script>
+
+<style>
+	.alarmList {
+		font-size: 14px;
+		height: 100%;
+		margin-top: 20rpx;
+	}
+
+	.alarmList .switchHead {
+		height: 30px;
+		display: flex;
+		justify-content: space-around;
+		align-items: center;
+	}
+
+	.alarmList .switchHead .boxList {
+		height: 100%;
+	}
+
+	.alarmList .switchHead .activeCss {
+		border-bottom: 2px solid #36A7F3;
+		color: #36A7F3;
+	}
+
+	.progress_list {
+		margin: 20rpx;
+	}
+
+	.progress_list view {
+		margin-top: 10px;
+	}
+
+	.progress_section_1 {
+		display: inline;
+		border-left: 2px solid red;
+		border-radius: 2px;
+		height: 5px;
+		background-color: red;
+		margin-right: 10px;
+	}
+
+	.progress_section_2 {
+		display: inline;
+		border-left: 2px solid #36A7F3;
+		border-radius: 2px;
+		height: 5px;
+		background-color: #36A7F3;
+		margin-right: 10px;
+	}
+
+	.progress_num {
+		font-size: 20px;
+		color: #000;
+		margin-right: 10rpx;
+
+	}
+
+	.progress_account {
+		font-size: 10px;
+	}
+</style>

+ 26 - 0
jp-mobile/uni_modules/uni-card/changelog.md

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

+ 270 - 0
jp-mobile/uni_modules/uni-card/components/uni-card/uni-card.vue

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

+ 90 - 0
jp-mobile/uni_modules/uni-card/package.json

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

+ 12 - 0
jp-mobile/uni_modules/uni-card/readme.md

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

+ 10 - 0
jp-mobile/uni_modules/uni-row/changelog.md

@@ -0,0 +1,10 @@
+## 1.0.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-row](https://uniapp.dcloud.io/component/uniui/uni-row)
+## 0.1.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.0.4(2021-05-12)
+- 新增 组件示例地址
+## 0.0.3(2021-02-05)
+- 调整为uni_modules目录规范
+- 新增uni-row组件

+ 317 - 0
jp-mobile/uni_modules/uni-row/components/uni-col/uni-col.vue

@@ -0,0 +1,317 @@
+<template>
+	<!-- #ifndef APP-NVUE -->
+	<view :class="['uni-col', sizeClass, pointClassList]" :style="{
+		paddingLeft:`${Number(gutter)}rpx`,
+		paddingRight:`${Number(gutter)}rpx`,
+	}">
+		<slot></slot>
+	</view>
+	<!-- #endif -->
+	<!-- #ifdef APP-NVUE -->
+	<!-- 在nvue上,类名样式不生效,换为style -->
+	<!-- 设置right正值失效,设置 left 负值 -->
+	<view :class="['uni-col']" :style="{
+		paddingLeft:`${Number(gutter)}rpx`,
+		paddingRight:`${Number(gutter)}rpx`,
+		width:`${nvueWidth}rpx`,
+		position:'relative',
+		marginLeft:`${marginLeft}rpx`,
+		left:`${right === 0 ? left : -right}rpx`
+	}">
+		<slot></slot>
+	</view>
+	<!-- #endif -->
+</template>
+
+<script>
+	/**
+	 * Col	布局-列
+	 * @description	搭配uni-row使用,构建布局。
+	 * @tutorial	https://ext.dcloud.net.cn/plugin?id=3958
+	 *
+	 * @property	{span} type = Number 栅格占据的列数
+	 * 						默认 24
+	 * @property	{offset} type = Number 栅格左侧的间隔格数
+	 * @property	{push} type = Number 栅格向右移动格数
+	 * @property	{pull} type = Number 栅格向左移动格数
+	 * @property	{xs} type = [Number, Object] <768px 响应式栅格数或者栅格属性对象
+	 * 						@description	Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
+	 * @property	{sm} type = [Number, Object] ≥768px 响应式栅格数或者栅格属性对象
+	 * 						@description	Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
+	 * @property	{md} type = [Number, Object] ≥992px 响应式栅格数或者栅格属性对象
+	 * 						@description	Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
+	 * @property	{lg} type = [Number, Object] ≥1200px 响应式栅格数或者栅格属性对象
+	 * 						@description	Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
+	 * @property	{xl} type = [Number, Object] ≥1920px 响应式栅格数或者栅格属性对象
+	 * 						@description	Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
+	 */
+	const ComponentClass = 'uni-col';
+
+	// -1 默认值,因为在微信小程序端只给Number会有默认值0
+	export default {
+		name: 'uniCol',
+		// #ifdef MP-WEIXIN
+		options: {
+			virtualHost: true // 在微信小程序中将组件节点渲染为虚拟节点,更加接近Vue组件的表现
+		},
+		// #endif
+		props: {
+			span: {
+				type: Number,
+				default: 24
+			},
+			offset: {
+				type: Number,
+				default: -1
+			},
+			pull: {
+				type: Number,
+				default: -1
+			},
+			push: {
+				type: Number,
+				default: -1
+			},
+			xs: [Number, Object],
+			sm: [Number, Object],
+			md: [Number, Object],
+			lg: [Number, Object],
+			xl: [Number, Object]
+		},
+		data() {
+			return {
+				gutter: 0,
+				sizeClass: '',
+				parentWidth: 0,
+				nvueWidth: 0,
+				marginLeft: 0,
+				right: 0,
+				left: 0
+			}
+		},
+		created() {
+			// 字节小程序中,在computed中读取$parent为undefined
+			let parent = this.$parent;
+
+			while (parent && parent.$options.componentName !== 'uniRow') {
+				parent = parent.$parent;
+			}
+
+			this.updateGutter(parent.gutter)
+			parent.$watch('gutter', (gutter) => {
+				this.updateGutter(gutter)
+			})
+
+			// #ifdef APP-NVUE
+			this.updateNvueWidth(parent.width)
+			parent.$watch('width', (width) => {
+				this.updateNvueWidth(width)
+			})
+			// #endif
+		},
+		computed: {
+			sizeList() {
+				let {
+					span,
+					offset,
+					pull,
+					push
+				} = this;
+
+				return {
+					span,
+					offset,
+					pull,
+					push
+				}
+			},
+			// #ifndef APP-NVUE
+			pointClassList() {
+				let classList = [];
+
+				['xs', 'sm', 'md', 'lg', 'xl'].forEach(point => {
+					const props = this[point];
+					if (typeof props === 'number') {
+						classList.push(`${ComponentClass}-${point}-${props}`)
+					} else if (typeof props === 'object' && props) {
+						Object.keys(props).forEach(pointProp => {
+							classList.push(
+								pointProp === 'span' ?
+								`${ComponentClass}-${point}-${props[pointProp]}` :
+								`${ComponentClass}-${point}-${pointProp}-${props[pointProp]}`
+							)
+						})
+					}
+				});
+
+				// 支付宝小程序使用 :class=[ ['a','b'] ],渲染错误
+				return classList.join(' ');
+			}
+			// #endif
+		},
+		methods: {
+			updateGutter(parentGutter) {
+				parentGutter = Number(parentGutter);
+				if (!isNaN(parentGutter)) {
+					this.gutter = parentGutter / 2
+				}
+			},
+			// #ifdef APP-NVUE
+			updateNvueWidth(width) {
+				// 用于在nvue端,span,offset,pull,push的计算
+				this.parentWidth = width;
+				['span', 'offset', 'pull', 'push'].forEach(size => {
+					const curSize = this[size];
+					if ((curSize || curSize === 0) && curSize !== -1) {
+						let RPX = 1 / 24 * curSize * width
+						RPX = Number(RPX);
+						switch (size) {
+							case 'span':
+								this.nvueWidth = RPX
+								break;
+							case 'offset':
+								this.marginLeft = RPX
+								break;
+							case 'pull':
+								this.right = RPX
+								break;
+							case 'push':
+								this.left = RPX
+								break;
+						}
+					}
+				});
+			}
+			// #endif
+		},
+		watch: {
+			sizeList: {
+				immediate: true,
+				handler(newVal) {
+					// #ifndef APP-NVUE
+					let classList = [];
+					for (let size in newVal) {
+						const curSize = newVal[size];
+						if ((curSize || curSize === 0) && curSize !== -1) {
+							classList.push(
+								size === 'span' ?
+								`${ComponentClass}-${curSize}` :
+								`${ComponentClass}-${size}-${curSize}`
+							)
+						}
+					}
+					// 支付宝小程序使用 :class=[ ['a','b'] ],渲染错误
+					this.sizeClass = classList.join(' ');
+					// #endif
+					// #ifdef APP-NVUE
+					this.updateNvueWidth(this.parentWidth);
+					// #endif
+				}
+			}
+		}
+	}
+</script>
+
+<style lang='scss' scoped>
+	/* breakpoints */
+	$--sm: 768px !default;
+	$--md: 992px !default;
+	$--lg: 1200px !default;
+	$--xl: 1920px !default;
+
+	$breakpoints: ('xs' : (max-width: $--sm - 1),
+	'sm' : (min-width: $--sm),
+	'md' : (min-width: $--md),
+	'lg' : (min-width: $--lg),
+	'xl' : (min-width: $--xl));
+
+	$layout-namespace: ".uni-";
+	$col: $layout-namespace+"col";
+
+	@function getSize($size) {
+		/* TODO 1/24 * $size * 100 * 1%; 使用计算后的值,为了解决 vue3 控制台报错 */
+		@return 0.04166666666 * $size * 100 * 1%;
+	}
+
+	@mixin res($key, $map:$breakpoints) {
+		@if map-has-key($map, $key) {
+			@media screen and #{inspect(map-get($map,$key))} {
+				@content;
+			}
+		}
+
+		@else {
+			@warn "Undeinfed point: `#{$key}`";
+		}
+	}
+
+	/* #ifndef APP-NVUE */
+	#{$col} {
+		float: left;
+		box-sizing: border-box;
+	}
+
+	#{$col}-0 {
+		/* #ifdef APP-NVUE */
+		width: 0;
+		height: 0;
+		margin-top: 0;
+		margin-right: 0;
+		margin-bottom: 0;
+		margin-left: 0;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		display: none;
+		/* #endif */
+	}
+
+	@for $i from 0 through 24 {
+		#{$col}-#{$i} {
+			width: getSize($i);
+		}
+
+		#{$col}-offset-#{$i} {
+			margin-left: getSize($i);
+		}
+
+		#{$col}-pull-#{$i} {
+			position: relative;
+			right: getSize($i);
+		}
+
+		#{$col}-push-#{$i} {
+			position: relative;
+			left: getSize($i);
+		}
+	}
+
+	@each $point in map-keys($breakpoints) {
+		@include res($point) {
+			#{$col}-#{$point}-0 {
+				display: none;
+			}
+
+			@for $i from 0 through 24 {
+				#{$col}-#{$point}-#{$i} {
+					width: getSize($i);
+				}
+
+				#{$col}-#{$point}-offset-#{$i} {
+					margin-left: getSize($i);
+				}
+
+				#{$col}-#{$point}-pull-#{$i} {
+					position: relative;
+					right: getSize($i);
+				}
+
+				#{$col}-#{$point}-push-#{$i} {
+					position: relative;
+					left: getSize($i);
+				}
+			}
+		}
+	}
+
+	/* #endif */
+</style>

+ 190 - 0
jp-mobile/uni_modules/uni-row/components/uni-row/uni-row.vue

@@ -0,0 +1,190 @@
+<template>
+	<view :class="[ 'uni-row', typeClass , justifyClass, alignClass, ]" :style="{
+		marginLeft:`${Number(marginValue)}rpx`,
+		marginRight:`${Number(marginValue)}rpx`,
+	}">
+		<slot></slot>
+	</view>
+</template>
+
+<script>
+	const ComponentClass = 'uni-row';
+	const modifierSeparator = '--';
+	/**
+	 * Row	布局-行
+	 * @description	流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。
+	 * @tutorial	https://ext.dcloud.net.cn/plugin?id=3958
+	 *
+	 * @property	{gutter} type = Number 栅格间隔
+	 * @property	{justify} type = String flex 布局下的水平排列方式
+	 * 						可选	start/end/center/space-around/space-between	start
+	 * 						默认值	start
+	 * @property	{align} type = String flex 布局下的垂直排列方式
+	 * 						可选	top/middle/bottom
+	 * 						默认值	top
+	 * @property	{width} type = String|Number nvue下需要自行配置宽度用于计算
+	 * 						默认值 750
+	 */
+
+
+	export default {
+		name: 'uniRow',
+		componentName: 'uniRow',
+		// #ifdef MP-WEIXIN
+		options: {
+			virtualHost: true // 在微信小程序中将组件节点渲染为虚拟节点,更加接近Vue组件的表现,可使用flex布局
+		},
+		// #endif
+		props: {
+			type: String,
+			gutter: Number,
+			justify: {
+				type: String,
+				default: 'start'
+			},
+			align: {
+				type: String,
+				default: 'top'
+			},
+			// nvue如果使用span等属性,需要配置宽度
+			width: {
+				type: [String, Number],
+				default: 750
+			}
+		},
+		created() {
+			// #ifdef APP-NVUE
+			this.type = 'flex';
+			// #endif
+		},
+		computed: {
+			marginValue() {
+				// #ifndef APP-NVUE
+				if (this.gutter) {
+					return -(this.gutter / 2);
+				}
+				// #endif
+				return 0;
+			},
+			typeClass() {
+				return this.type === 'flex' ? `${ComponentClass + modifierSeparator}flex` : '';
+			},
+			justifyClass() {
+				return this.justify !== 'start' ? `${ComponentClass + modifierSeparator}flex-justify-${this.justify}` : ''
+			},
+			alignClass() {
+				return this.align !== 'top' ? `${ComponentClass + modifierSeparator}flex-align-${this.align}` : ''
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	$layout-namespace: ".uni-";
+	$row:$layout-namespace+"row";
+	$modifier-separator: "--";
+
+	@mixin utils-clearfix {
+		$selector: &;
+
+		@at-root {
+
+			/* #ifndef APP-NVUE */
+			#{$selector}::before,
+			#{$selector}::after {
+				display: table;
+				content: "";
+			}
+
+			#{$selector}::after {
+				clear: both;
+			}
+
+			/* #endif */
+		}
+
+	}
+
+	@mixin utils-flex ($direction: row) {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: $direction;
+	}
+
+	@mixin set-flex($state) {
+		@at-root &-#{$state} {
+			@content
+		}
+	}
+
+	#{$row} {
+		position: relative;
+		flex-direction: row;
+
+		/* #ifdef APP-NVUE */
+		flex: 1;
+		/* #endif */
+
+		/* #ifndef APP-NVUE */
+		box-sizing: border-box;
+		/* #endif */
+
+		// 非nvue使用float布局
+		@include utils-clearfix;
+
+		// 在QQ、字节、百度小程序平台,编译后使用shadow dom,不可使用flex布局,使用float
+		@at-root {
+
+			/* #ifndef MP-QQ || MP-TOUTIAO || MP-BAIDU */
+			&#{$modifier-separator}flex {
+				@include utils-flex;
+				flex-wrap: wrap;
+				flex: 1;
+
+				&:before,
+				&:after {
+					/* #ifndef APP-NVUE */
+					display: none;
+					/* #endif */
+				}
+
+				@include set-flex(justify-center) {
+					justify-content: center;
+				}
+
+				@include set-flex(justify-end) {
+					justify-content: flex-end;
+				}
+
+				@include set-flex(justify-space-between) {
+					justify-content: space-between;
+				}
+
+				@include set-flex(justify-space-around) {
+					justify-content: space-around;
+				}
+
+				@include set-flex(align-middle) {
+					align-items: center;
+				}
+
+				@include set-flex(align-bottom) {
+					align-items: flex-end;
+				}
+			}
+
+			/* #endif */
+		}
+
+	}
+
+	// 字节、QQ配置后不生效
+	// 此处用法无法使用scoped
+	/* #ifdef MP-WEIXIN || MP-TOUTIAO || MP-QQ */
+	:host {
+		display: block;
+	}
+
+	/* #endif */
+</style>

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

@@ -0,0 +1,87 @@
+{
+  "id": "uni-row",
+  "displayName": "uni-row 布局-行",
+  "version": "1.0.0",
+  "description": "流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "栅格",
+    "布局",
+    "layout"
+],
+  "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": "u"
+        }
+      }
+    }
+  }
+}

+ 10 - 0
jp-mobile/uni_modules/uni-row/readme.md

@@ -0,0 +1,10 @@
+## Layout 布局
+
+> **组件名 uni-row、uni-col**
+> 代码块: `uRow`、`uCol`
+
+
+流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-row)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839