index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <template>
  2. <view class="yt-txl-container">
  3. <view class="search">
  4. <input type="text" @input="inputFunc" class="s-input" placeholder="搜索" />
  5. </view>
  6. <view class="scroll" :style="index ? '' :'right:25upx'">
  7. <scroll-view :scroll-into-view="to" scroll-y style="width: 100%;height: 100%;">
  8. <view class="info">
  9. <view style="background:#E6B728" class="icon">
  10. <tui-icon name="friendadd" :size="20" color="#fff"></tui-icon>
  11. </view>
  12. <view class="item" @tap="newblood">
  13. <text class="name">新的成员</text>
  14. </view>
  15. </view>
  16. <view :id="o.key" v-for="(o,i) in resource" :key="i">
  17. <view class="p" >{{o.key}}</view>
  18. <tui-swipe-action :actions="actions2" :showMask="false" @click="handlerButton2">
  19. <template v-slot:content>
  20. <view v-for="(item,index) in o.data" class="info" :key="index">
  21. <view :style="'background:'+color" class="icon" @tap="situation">
  22. <image class="photo" :src="item[photo]"></image>
  23. </view>
  24. <view class="item">
  25. <text class="name">{{item[name]}}</text>
  26. </view>
  27. </view>
  28. </template>
  29. </tui-swipe-action>
  30. </view>
  31. <view style="height: 60upx;"></view>
  32. </scroll-view>
  33. </view>
  34. <view class="flag" v-if="index">
  35. <scroll-view scroll-y="true" :show-scrollbar="false" class="flag-scroll" style="width: 100%;height: 100%;">
  36. <view @click="toFunc(o.key)" class="flag-key" v-for="(o,i) in resource" :key="i">
  37. {{o.key}}
  38. </view>
  39. </scroll-view>
  40. </view>
  41. <uni-popup ref="popup" type="center">
  42. <view class="tui-modal-custom" style="padding: 20px 32px;border-radius: 12px;background-color: #fff;">
  43. <input placeholder="姓名(必填)" class="tui-modal-input" v-model="name1" />
  44. <input placeholder="性别" class="tui-modal-input" v-model="sex" />
  45. <input placeholder="生日" class="tui-modal-input" v-model="birthday" />
  46. <input placeholder="手机号" class="tui-modal-input" v-model="phone" />
  47. <input placeholder="配偶" class="tui-modal-input" v-model="spouse" />
  48. <input placeholder="状态(求学/工作)" class="tui-modal-input" v-model="state" />
  49. <tui-button height="72rpx" :size="28" shape="circle" @click="close">提交</tui-button>
  50. </view>
  51. </uni-popup>
  52. </view>
  53. </template>
  54. <script>
  55. import tuiIcon from "@/components/thorui/tui-icon/tui-icon"
  56. import tuiSwipeAction from "@/components/thorui/tui-swipe-action/tui-swipe-action"
  57. import tuiButton from "@/components/thorui/tui-button/tui-button"
  58. 'use strict';
  59. let pinyin = new(require('./pinyin'))({
  60. charCase: 0
  61. });
  62. export default {
  63. components: {
  64. tuiIcon,
  65. tuiSwipeAction,
  66. tuiButton
  67. },
  68. props: {
  69. datas: {
  70. type: Array,
  71. default () {
  72. return [];
  73. }
  74. },
  75. name: {
  76. type: String,
  77. default () {
  78. return "name";
  79. }
  80. },
  81. photo: {
  82. type: String,
  83. default () {
  84. return "photo";
  85. }
  86. },
  87. index: {
  88. type: Boolean,
  89. default: true
  90. },
  91. color: {
  92. type:String,
  93. default:"#ffffff"
  94. }
  95. },
  96. data() {
  97. return {
  98. resource: [],
  99. chars: [],
  100. to: "",
  101. cache:[],
  102. actions2: [
  103. {
  104. name: '编辑',
  105. color: '#fff',
  106. fontsize: 30,
  107. width: 70,
  108. background: '#E6B728'
  109. },
  110. {
  111. name: '删除',
  112. color: '#fff',
  113. fontsize: 30, //单位rpx
  114. width: 70, //单位px
  115. background: '#FD3B31'
  116. }
  117. ],
  118. open:false,
  119. name1:'',
  120. sex:'',
  121. birthday:'',
  122. phone:'',
  123. spouse:'',
  124. state:'',
  125. value:'',
  126. };
  127. },
  128. watch: {
  129. datas(r) {
  130. if (!(r instanceof Array)) {
  131. console.log("the props datas type must be array")
  132. return
  133. }
  134. this._parseData(r)
  135. }
  136. },
  137. methods: {
  138. situation: function() {
  139. uni.navigateTo({
  140. url: '../../pages/family/situation/situation'
  141. });
  142. },
  143. handlerButton2(e) {
  144. let index = e.index + 1;
  145. if (index === 1){
  146. this.$refs.popup.open()
  147. } else if (index===2) {
  148. console.log('删除成功')
  149. }
  150. },
  151. close(){
  152. this.$refs.popup.close()
  153. console.log('保存成功')
  154. },
  155. newblood: function() {
  156. uni.navigateTo({
  157. url: '/pages/family/newblood/newblood'
  158. });
  159. },
  160. toFunc(o) {
  161. this.to = o
  162. },
  163. inputFunc(r){ //搜索功能
  164. if(!r.detail.value) {
  165. this.resource = this.cache
  166. return
  167. }
  168. let temp = []
  169. this.cache.forEach(o => {
  170. o.data.forEach(item =>{
  171. if(item[this.name].indexOf(r.detail.value) > -1){ // 匹配到
  172. // 确定当前这个元素的key是谁
  173. let key = o.key
  174. // 找到temp中的key
  175. let index = 0 //下标
  176. let find = false // 数据是否存在
  177. for(let d in temp){
  178. if(temp[d].key === o.key){
  179. index = d
  180. find = true
  181. }
  182. }
  183. if(find){ // 如果key已经存在,直接插入数据
  184. temp[index].data.push(item)
  185. } else { // 不存在初始化一个并存入
  186. temp.push({
  187. key:o.key,
  188. data:[item]
  189. })
  190. }
  191. }
  192. })
  193. })
  194. this.resource = temp
  195. },
  196. _type(val){
  197. return Object.prototype.toString.call(val).slice(8,-1).toLowerCase()
  198. },
  199. _parseData(r) {
  200. // 生成a-z的数组
  201. let data = [];
  202. this.chars = []
  203. for (let i = 65; i <= 90; i++) {
  204. let key = String.fromCharCode(i)
  205. data.push({"key":key,data:[]})
  206. this.chars.push(key)
  207. }
  208. if(this._type(r) === "array") {
  209. // 填充数据
  210. r.forEach(o => {
  211. // 找到char的位置
  212. data.forEach( (item,index) => {
  213. let a = this._parseChar(o[this.name || 'name'])
  214. if(item.key === a){
  215. data[index].data.push(o)
  216. }
  217. })
  218. })
  219. }
  220. // 组合最后数据并踢出没有匹配到a-z中的任意数据
  221. let finalData = []
  222. for (let i in data) {
  223. if(data[i].data.length > 0){
  224. finalData.push(data[i])
  225. }
  226. }
  227. this.resource = finalData
  228. this.cache = finalData
  229. finalData = null
  230. },
  231. _parseChar(name) {
  232. if (Object.prototype.toString.call(name).slice(8, -1) !== 'String') {
  233. console.error("name is not string")
  234. return
  235. }
  236. let chars = pinyin.getFullChars(name);
  237. return chars[0].toUpperCase()
  238. }
  239. },
  240. mounted() {
  241. this._parseData(this.datas)
  242. }
  243. };
  244. </script>
  245. <style>
  246. page {
  247. background: #f4f4f4;
  248. }
  249. .tui-modal-input {
  250. width: 80%;
  251. border-bottom: 1rpx solid #e6e6e6;
  252. margin: 30rpx auto 50rpx;
  253. padding-bottom: 20rpx;
  254. font-size: 32rpx;
  255. }
  256. .search {
  257. width: 100%;
  258. height: 120upx;
  259. display: flex;
  260. justify-content: center;
  261. align-items: center;
  262. }
  263. .s-input {
  264. width: 100%;
  265. height: 80upx;
  266. background: url('data:image/png;base64,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') 20upx center no-repeat #fff;
  267. background-size: 40upx;
  268. text-indent: 80upx;
  269. }
  270. .scroll {
  271. position: absolute;
  272. top: 120upx;
  273. bottom: 25upx;
  274. width: 100%;
  275. }
  276. .p {
  277. position: sticky;
  278. top: 0;
  279. left: 0;
  280. background: #f4f4f4;
  281. font-size: 28upx;
  282. margin-bottom: 10upx;
  283. text-indent: 40upx;
  284. z-index: 1;
  285. font-weight: bold;
  286. }
  287. .info {
  288. display: flex;
  289. justify-content: flex-start;
  290. align-items: center;
  291. margin-bottom: 4upx;
  292. padding: 20upx 25upx;
  293. background: #fff;
  294. }
  295. .icon {
  296. width: 64upx;
  297. height: 64upx;
  298. border-radius: 50%;
  299. margin-right: 20upx;
  300. display: flex;
  301. justify-content: center;
  302. align-items: center;
  303. font-size: 30upx;
  304. color: #fff;
  305. }
  306. .photo {
  307. width: 100%;
  308. height: 100%;
  309. border-radius: 50%;
  310. display: flex;
  311. justify-content: center;
  312. align-items: center;
  313. font-size: 30upx;
  314. color: #fff;
  315. }
  316. .item {
  317. display: flex;
  318. flex-direction: column;
  319. justify-content: space-around;
  320. }
  321. .flag {
  322. width: 50rpx;
  323. position: fixed;
  324. top: 200upx;
  325. right: 0;
  326. bottom: 0;
  327. z-index: 99999;
  328. /* #ifdef H5 */
  329. top: 300upx;
  330. /* #endif */
  331. }
  332. .flag-scroll {
  333. padding-top: 10upx;
  334. }
  335. .flag-key {
  336. padding: 0;
  337. margin: 0 auto 2upx auto;
  338. width: 30upx;
  339. height: 30upx;
  340. border-radius: 50%;
  341. color: #000;
  342. font-weight: bold;
  343. display: flex;
  344. justify-content: center;
  345. align-items: center;
  346. font-size: 20upx;
  347. }
  348. </style>