@sy-common/organize-select-help 1.0.0-beta.66 → 1.0.0-beta.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.vue +653 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sy-common/organize-select-help",
3
- "version": "1.0.0-beta.66",
3
+ "version": "1.0.0-beta.68",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "author": "lambo",
package/src/index.vue CHANGED
@@ -178,6 +178,71 @@
178
178
  </div>
179
179
  </div>
180
180
  </TabPane>
181
+ <TabPane label="组织选择" name="orgNew" v-if="name.includes('orgNew')">
182
+ <div class="tab org-new-tab">
183
+ <div class="org-new-header">
184
+ <Input v-model="orgNewSearch" @on-enter="searchOrgNew" @on-search="searchOrgNew" search placeholder="搜索组织节点名称(如:办公室)" style="width: 100%;"/>
185
+ <div class="org-new-actions">
186
+ <Button type="primary" ghost @click="expandAllOrgNew">展开全部</Button>
187
+ <Button type="primary" ghost @click="collapseAllOrgNew">折叠全部</Button>
188
+ <!-- <Button type="default" @click="clearOrgNew">清空</Button>-->
189
+ </div>
190
+ </div>
191
+ <div class="org-new-content">
192
+ <div class="org-card" v-for="(province, index) in filteredOrgNewTree" :key="province.orgUnitId">
193
+ <div class="org-card-header" @click="toggleProvinceExpand(province)">
194
+ <div class="org-card-title" @click.stop="addOrgNewItem(province)">
195
+ <img src="./assets/icon.png" alt="" style="margin-right: 8px; width: 14px; height: 14px;"/>
196
+ {{ province.title }}
197
+ </div>
198
+ <div class="org-card-actions" v-if="province.children && province.children.length > 0">
199
+ <Button type="text" @click.stop="selectAllProvinceOrgNew(province)">全选(包含下级)</Button>
200
+ <Icon size="20" :type="province.expand ? 'md-arrow-dropdown' : 'md-arrow-dropright'" style="margin-left: 8px;"/>
201
+ </div>
202
+ </div>
203
+ <div class="org-card-body" v-if="province.expand && province.children && province.children.length > 0">
204
+ <div class="city-card" v-for="city in province.children" :key="city.orgUnitId">
205
+ <div class="city-card-header" @click="toggleCityExpand(city)">
206
+ <div class="city-card-title" @click.stop="addOrgNewItem(city)">
207
+ <img src="./assets/icon.png" alt="" style="margin-right: 8px; width: 14px; height: 14px;"/>
208
+ {{ city.title }}
209
+ </div>
210
+ <div class="city-card-actions" v-if="city.children && city.children.length > 0">
211
+ <Button type="text" @click.stop="selectAllCityOrgNew(city)">全选(包含下级)</Button>
212
+ <!-- <Button type="text" @click.stop="selectAllCityLevelOrgNew(city)">全选市本级</Button>-->
213
+ <Icon size="20" :type="city.expand ? 'md-arrow-dropdown' : 'md-arrow-dropright'" style="margin-left: 8px;"/>
214
+ </div>
215
+ </div>
216
+ <div class="city-card-body" v-if="city.expand && city.children && city.children.length > 0">
217
+ <div class="district-grid">
218
+ <div class="district-item" v-for="district in city.children" :key="district.orgUnitId">
219
+ <div class="district-header" @click="toggleDistrictExpand(district)">
220
+ <div class="district-title" @click.stop="addOrgNewItem(district)">
221
+ <img src="./assets/icon.png" alt="" style="margin-right: 8px; width: 14px; height: 14px;"/>
222
+ {{ district.title }}
223
+ </div>
224
+ <div class="district-actions" v-if="district.children && district.children.length > 0">
225
+ <Button type="text" @click.stop="selectAllDistrictOrgNew(district)">全选</Button>
226
+ <Icon size="20" :type="district.expand ? 'md-arrow-dropdown' : 'md-arrow-dropright'" style="margin-left: 8px;"/>
227
+ </div>
228
+ </div>
229
+ <div class="district-body" v-if="district.expand && district.children && district.children.length > 0">
230
+ <div class="org-unit-item" v-for="unit in district.children" :key="unit.orgUnitId">
231
+ <div class="unit-title" @click="addOrgNewItem(unit)">
232
+ <img src="./assets/icon.png" alt="" style="margin-right: 8px; width: 14px; height: 14px;"/>
233
+ {{ unit.title }}
234
+ </div>
235
+ </div>
236
+ </div>
237
+ </div>
238
+ </div>
239
+ </div>
240
+ </div>
241
+ </div>
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </TabPane>
181
246
  </Tabs>
182
247
  </div>
183
248
  <div class="form-content">
@@ -214,7 +279,7 @@
214
279
  <!-- 直接选择人员:-->
215
280
  <div v-if="name.includes('staff')">
216
281
  <div class="group-box flex-r-bt">
217
- <div>直接选择人员:</div>
282
+ <div>选择人员:</div>
218
283
  <div class="clear-btn" @click="clearStaff">清除全部</div>
219
284
  </div>
220
285
  <div class="group-list-content">
@@ -222,7 +287,21 @@
222
287
  <span>{{item.name}}</span>
223
288
  <img class="clear-icon" src="./assets/delete.png" alt="" @click="clearStaffByIndex(index)">
224
289
  </p>
225
- <p style="color:#CCCCCC" class="list-item" v-if="!staffList.length">未选择直接选择人员</p>
290
+ <p style="color:#CCCCCC" class="list-item" v-if="!staffList.length">未选择人员</p>
291
+ </div>
292
+ </div>
293
+ <!-- 组织选择(新):-->
294
+ <div v-if="name.includes('orgNew')">
295
+ <div class="group-box flex-r-bt">
296
+ <div>组织选择:</div>
297
+ <div class="clear-btn" @click="clearOrgNewList">清除全部</div>
298
+ </div>
299
+ <div class="group-list-content">
300
+ <p class="list-item flex-r-bt" v-for="(item,index) in orgNewList" :key="item.id">
301
+ <span>{{item.title}}</span>
302
+ <img class="clear-icon" src="./assets/delete.png" alt="" @click="clearOrgNewByIndex(index)">
303
+ </p>
304
+ <p style="color:#CCCCCC" class="list-item" v-if="!orgNewList.length">未选择组织节点</p>
226
305
  </div>
227
306
  </div>
228
307
  </div>
@@ -315,6 +394,13 @@ export default {
315
394
  // 缓存原始组织树/岗位树数据
316
395
  originalOrgTree: [], // 组织Tab原始树缓存
317
396
  originalPostTree: [], // 岗位Tab原始树缓存
397
+ staffTreeInited: false, // 组织树初始化完成标记(用于需求3)
398
+ //组织选择(新)
399
+ orgNewSearch: '',
400
+ orgNewTree: [],
401
+ proOrgNewList: [],
402
+ includeLevelOrgNew: [],
403
+ orgNewList: []
318
404
  }
319
405
  },
320
406
  mounted() {
@@ -325,6 +411,7 @@ export default {
325
411
  this.initOrgOrgTree()
326
412
  this.initPostOrgTree()
327
413
  this.initStaffOrgTree()
414
+ this.initOrgNewTree()
328
415
  },
329
416
 
330
417
  methods:{
@@ -1266,11 +1353,18 @@ export default {
1266
1353
  clearStaffByIndex(index){
1267
1354
  this.staffList.splice(index,1)
1268
1355
  },
1356
+ clearOrgNewList(){
1357
+ this.orgNewList = []
1358
+ },
1359
+ clearOrgNewByIndex(index){
1360
+ this.orgNewList.splice(index,1)
1361
+ },
1269
1362
  confirm(){
1270
1363
  const v = {
1271
1364
  orgList:this.orgList,
1272
1365
  postList:this.postList,
1273
- staffList:this.staffList
1366
+ staffList:this.staffList,
1367
+ orgNewList:this.orgNewList
1274
1368
  }
1275
1369
  this.$emit('confirm',deepCopy(v))
1276
1370
  },
@@ -1859,6 +1953,280 @@ export default {
1859
1953
  this.updateTreeNodesStatus(children, expandIds, checkedIds);
1860
1954
  }
1861
1955
  });
1956
+ },
1957
+ // 组织选择(新)相关方法
1958
+ async initOrgNewTree() {
1959
+ try {
1960
+ const res = await ajax.get('/pub-manage-server/pub/personHelpBox/q/getFullOrgUnitTree');
1961
+ if (res.data.code === 1) {
1962
+ // 直接使用返回的完整树形结构
1963
+ const treeData = res.data.data || [];
1964
+ // 处理树形数据,添加必要的字段
1965
+ const processedTree = this.processOrgNewTree(treeData);
1966
+ this.orgNewTree = this.safeDeepCopy(processedTree);
1967
+ }
1968
+ } catch (e) {
1969
+ this.$Message.error("组织选择(新)树初始化失败!");
1970
+ console.error(e);
1971
+ }
1972
+ },
1973
+ buildOrgNewTree(items) {
1974
+ const map = {};
1975
+ const roots = [];
1976
+ const copiedItems = this.safeDeepCopy(items);
1977
+
1978
+ copiedItems.forEach(item => {
1979
+ if (!item.orgUnitId) return;
1980
+ map[item.orgUnitId] = this.safeDeepCopy({
1981
+ ...item,
1982
+ orgChildrenList: [],
1983
+ children: [],
1984
+ title: item.orgUnitName || item.orgNodeName || item.name || `未命名组织(${item.orgUnitId || ''})`,
1985
+ expand: false,
1986
+ checked: false
1987
+ });
1988
+ });
1989
+
1990
+ copiedItems.forEach(item => {
1991
+ if (!item.orgUnitId || !map[item.orgUnitId]) return;
1992
+
1993
+ const node = map[item.orgUnitId];
1994
+ if (!item.parentOrgUnitId || !map[item.parentOrgUnitId]) {
1995
+ node.expand = true;
1996
+ roots.push(node);
1997
+ } else {
1998
+ const parent = map[item.parentOrgUnitId];
1999
+ parent.orgChildrenList.push(node);
2000
+ parent.children.push(node);
2001
+ parent.leafNode = false;
2002
+ }
2003
+ });
2004
+ return roots;
2005
+ },
2006
+ // 处理新接口返回的组织树数据
2007
+ processOrgNewTree(treeData) {
2008
+ if (!Array.isArray(treeData)) return [];
2009
+
2010
+ return treeData.map(node => {
2011
+ // 添加必要的字段
2012
+ const processedNode = {
2013
+ ...node,
2014
+ title: node.orgNodeName || node.orgUnitName || `未命名组织(${node.orgUnitId || ''})`,
2015
+ expand: false,
2016
+ checked: false,
2017
+ orgChildrenList: node.children || []
2018
+ };
2019
+
2020
+ // 递归处理子节点
2021
+ if (processedNode.children && processedNode.children.length > 0) {
2022
+ processedNode.children = this.processOrgNewTree(processedNode.children);
2023
+ processedNode.expand = true; // 默认展开有子节点的节点
2024
+ }
2025
+
2026
+ return processedNode;
2027
+ });
2028
+ },
2029
+ searchOrgNew() {
2030
+ // 搜索功能已通过计算属性实现,这里可以添加额外的逻辑
2031
+ },
2032
+ toggleProvinceExpand(province) {
2033
+ // 只有有子节点时才允许展开/折叠
2034
+ if (province.children && province.children.length > 0) {
2035
+ province.expand = !province.expand;
2036
+ // 同步更新原始数据中的节点状态
2037
+ this.updateOriginalNodeExpand(province);
2038
+ }
2039
+ },
2040
+ toggleCityExpand(city) {
2041
+ // 只有有子节点时才允许展开/折叠
2042
+ if (city.children && city.children.length > 0) {
2043
+ city.expand = !city.expand;
2044
+ // 同步更新原始数据中的节点状态
2045
+ this.updateOriginalNodeExpand(city);
2046
+ }
2047
+ },
2048
+ toggleDistrictExpand(district) {
2049
+ // 只有有子节点时才允许展开/折叠
2050
+ if (district.children && district.children.length > 0) {
2051
+ district.expand = !district.expand;
2052
+ // 同步更新原始数据中的节点状态
2053
+ this.updateOriginalNodeExpand(district);
2054
+ }
2055
+ },
2056
+ updateOriginalNodeExpand(node) {
2057
+ // 查找并更新原始数据中的节点状态
2058
+ const findAndUpdate = (nodes) => {
2059
+ for (let i = 0; i < nodes.length; i++) {
2060
+ if (nodes[i].orgUnitId === node.orgUnitId) {
2061
+ nodes[i].expand = node.expand;
2062
+ return true;
2063
+ }
2064
+ if (nodes[i].children && nodes[i].children.length > 0) {
2065
+ if (findAndUpdate(nodes[i].children)) {
2066
+ return true;
2067
+ }
2068
+ }
2069
+ }
2070
+ return false;
2071
+ };
2072
+ findAndUpdate(this.orgNewTree);
2073
+ },
2074
+ selectAllProvinceOrgNew(province) {
2075
+ // 全选并添加到已选择条件框,包含下级节点
2076
+ this.addOrgNewItemWithChildren(province, true);
2077
+ },
2078
+ selectAllCityOrgNew(city) {
2079
+ // 全选并添加到已选择条件框,包含下级节点
2080
+ this.addOrgNewItemWithChildren(city, true);
2081
+ },
2082
+ selectAllCityLevelOrgNew(city) {
2083
+ // 全选市本级并添加到已选择条件框,包含下级节点
2084
+ if (city.children && city.children.length > 0) {
2085
+ const cityLevel = city.children[0];
2086
+ this.addOrgNewItemWithChildren(cityLevel, true);
2087
+ }
2088
+ },
2089
+ selectAllDistrictOrgNew(district) {
2090
+ // 全选并添加到已选择条件框,包含下级节点
2091
+ this.addOrgNewItemWithChildren(district, true);
2092
+ },
2093
+ addOrgNewItemWithChildren(node, includeLevel) {
2094
+ if (!node.orgUnitId) return this.$Message.error("组织节点无效!");
2095
+
2096
+ // 检查是否已存在
2097
+ const id = includeLevel ? `01-${node.orgUnitId}` : `00-${node.orgUnitId}`;
2098
+ const existingIndex = this.orgNewList.findIndex(item => item.id === id);
2099
+ if (existingIndex > -1) {
2100
+ this.$Message.warning(`【${node.title}】已在选择列表中`);
2101
+ return;
2102
+ }
2103
+
2104
+ // 创建组织条件项
2105
+ const orgItem = {
2106
+ ...node,
2107
+ title: includeLevel ? `${node.title}(包含下级组织节点)` : node.title,
2108
+ id: id,
2109
+ includeLevel: includeLevel,
2110
+ orgNodeName: node.orgNodeName || node.title
2111
+ };
2112
+
2113
+ // 添加到已选择列表
2114
+ this.orgNewList.push(orgItem);
2115
+ this.$Message.success(`已添加【${orgItem.title}】`);
2116
+ },
2117
+ isProvinceAllSelected(province) {
2118
+ if (!province.children || province.children.length === 0) return false;
2119
+ return province.children.every(city => this.isCityAllSelected(city));
2120
+ },
2121
+ isCityAllSelected(city) {
2122
+ if (!city.children || city.children.length === 0) return false;
2123
+ return city.children.every(district => this.isDistrictAllSelected(district));
2124
+ },
2125
+ isCityLevelAllSelected(city) {
2126
+ // 检查市本级是否全选
2127
+ if (!city.children || city.children.length === 0) return false;
2128
+ // 假设第一个子节点是市本级
2129
+ const cityLevel = city.children[0];
2130
+ return this.isDistrictAllSelected(cityLevel);
2131
+ },
2132
+ isDistrictAllSelected(district) {
2133
+ if (!district.children || district.children.length === 0) return false;
2134
+ return district.children.every(unit => unit.checked);
2135
+ },
2136
+ setProvinceChecked(province, checked) {
2137
+ if (province.children) {
2138
+ province.children.forEach(city => {
2139
+ this.setCityChecked(city, checked);
2140
+ });
2141
+ }
2142
+ },
2143
+ setCityChecked(city, checked) {
2144
+ if (city.children) {
2145
+ city.children.forEach(district => {
2146
+ this.setDistrictChecked(district, checked);
2147
+ });
2148
+ }
2149
+ },
2150
+ setCityLevelChecked(city, checked) {
2151
+ if (city.children && city.children.length > 0) {
2152
+ // 只设置市本级(第一个子节点)
2153
+ const cityLevel = city.children[0];
2154
+ this.setDistrictChecked(cityLevel, checked);
2155
+ }
2156
+ },
2157
+ setDistrictChecked(district, checked) {
2158
+ if (district.children) {
2159
+ district.children.forEach(unit => {
2160
+ unit.checked = checked;
2161
+ });
2162
+ }
2163
+ },
2164
+ handleOrgNewUnitChange(unit) {
2165
+ // 处理组织单位选择变化
2166
+ this.collectOrgNewCheckedUnits();
2167
+ },
2168
+ collectOrgNewCheckedUnits() {
2169
+ this.proOrgNewList = [];
2170
+ this.collectCheckedUnits(this.orgNewTree);
2171
+ },
2172
+ collectCheckedUnits(nodeList) {
2173
+ if (!Array.isArray(nodeList)) return;
2174
+ nodeList.forEach(node => {
2175
+ if (node.checked) {
2176
+ this.proOrgNewList.push({
2177
+ ...node,
2178
+ orgNodeName: node.orgNodeName || node.title || `未命名组织(${node.orgUnitId})`
2179
+ });
2180
+ }
2181
+ if (node.children && node.children.length > 0) {
2182
+ this.collectCheckedUnits(node.children);
2183
+ }
2184
+ });
2185
+ },
2186
+ expandAllOrgNew() {
2187
+ this.setAllExpand(this.orgNewTree, true);
2188
+ },
2189
+ collapseAllOrgNew() {
2190
+ this.setAllExpand(this.orgNewTree, false);
2191
+ },
2192
+ setAllExpand(nodeList, expand) {
2193
+ if (!Array.isArray(nodeList)) return;
2194
+ nodeList.forEach(node => {
2195
+ node.expand = expand;
2196
+ if (node.children && node.children.length > 0) {
2197
+ this.setAllExpand(node.children, expand);
2198
+ }
2199
+ });
2200
+ },
2201
+ clearOrgNew() {
2202
+ this.clearAllCheckedOrgNew(this.orgNewTree);
2203
+ this.proOrgNewList = [];
2204
+ this.orgNewSearch = '';
2205
+ },
2206
+ clearAllCheckedOrgNew(nodeList) {
2207
+ if (!Array.isArray(nodeList)) return;
2208
+ nodeList.forEach(node => {
2209
+ node.checked = false;
2210
+ if (node.children && node.children.length > 0) {
2211
+ this.clearAllCheckedOrgNew(node.children);
2212
+ }
2213
+ });
2214
+ },
2215
+ addOrgNewItem(node) {
2216
+ // 调用通用方法,不包含下级节点
2217
+ this.addOrgNewItemWithChildren(node, false);
2218
+ },
2219
+ addOrgNewList() {
2220
+ const validOrgList = this.proOrgNewList.filter(node => node.orgUnitId);
2221
+ if (!validOrgList.length) return this.$Message.error("请先选择组织节点!");
2222
+
2223
+ validOrgList.forEach(node => {
2224
+ this.addOrgNewItemWithChildren(node, false);
2225
+ });
2226
+
2227
+ // 清空选中状态
2228
+ this.clearAllCheckedOrgNew(this.orgNewTree);
2229
+ this.proOrgNewList = [];
1862
2230
  }
1863
2231
 
1864
2232
  },
@@ -1870,7 +2238,44 @@ export default {
1870
2238
  let l1 = this.orgList.length?1:0;
1871
2239
  let l2 = this.postList.length?1:0;
1872
2240
  let l3 = this.staffList.length?1:0;
1873
- return l1+l2+l3
2241
+ let l4 = this.orgNewList.length?1:0;
2242
+ return l1+l2+l3+l4
2243
+ },
2244
+ filteredOrgNewTree() {
2245
+ // 前端过滤,模糊匹配
2246
+ const searchTerm = this.orgNewSearch.toLowerCase().trim();
2247
+ if (!searchTerm) {
2248
+ return this.orgNewTree;
2249
+ }
2250
+
2251
+ // 递归过滤函数
2252
+ const filterTree = (nodes) => {
2253
+ return nodes.map(node => {
2254
+ // 检查当前节点是否匹配
2255
+ const isMatch = node.title.toLowerCase().includes(searchTerm);
2256
+
2257
+ // 递归过滤子节点
2258
+ let filteredChildren = [];
2259
+ if (node.children && node.children.length > 0) {
2260
+ filteredChildren = filterTree(node.children);
2261
+ }
2262
+
2263
+ // 如果当前节点匹配或有匹配的子节点,则保留该节点
2264
+ if (isMatch || filteredChildren.length > 0) {
2265
+ // 创建一个新对象,保留原始节点的所有属性,包括expand状态
2266
+ return {
2267
+ ...node,
2268
+ children: filteredChildren
2269
+ };
2270
+ }
2271
+
2272
+ // 不匹配且没有匹配的子节点,则过滤掉
2273
+ return null;
2274
+ }).filter(Boolean); // 过滤掉null值
2275
+ };
2276
+
2277
+ // 直接使用原始树数据,不需要深拷贝
2278
+ return filterTree(this.orgNewTree);
1874
2279
  }
1875
2280
  },
1876
2281
  watch:{
@@ -1894,6 +2299,12 @@ export default {
1894
2299
  })
1895
2300
  this.postList = postList
1896
2301
  this.staffList = map.staffList || []
2302
+ let orgNewList = map.orgNewList || []
2303
+ orgNewList.forEach(item=>{
2304
+ item.title = item.includeLevel?`${item.orgNodeName}(包含下级组织节点)`:item.orgNodeName
2305
+ item.id = item.includeLevel?('01'+'-' + item.orgUnitId):('00'+'-'+item.orgUnitId)
2306
+ })
2307
+ this.orgNewList = orgNewList
1897
2308
  },
1898
2309
  deep: true,
1899
2310
  immediate: true,
@@ -2287,6 +2698,244 @@ export default {
2287
2698
  background-color: #f5f5f5;
2288
2699
  }
2289
2700
 
2701
+ /* 组织选择(新)样式 */
2702
+ .org-new-tab {
2703
+ .org-new-header {
2704
+ display: flex;
2705
+ justify-content: space-between;
2706
+ align-items: center;
2707
+ margin-bottom: 16px;
2708
+ flex-wrap: wrap;
2709
+ gap: 10px;
2710
+ }
2711
+
2712
+ .org-new-actions {
2713
+ display: flex;
2714
+ gap: 10px;
2715
+ }
2716
+
2717
+ .org-new-content {
2718
+ max-height: 500px;
2719
+ overflow-y: auto;
2720
+ border: 1px solid #EAECF0;
2721
+ border-radius: 4px;
2722
+ padding: 16px;
2723
+ margin-bottom: 16px;
2724
+ }
2725
+
2726
+ .org-card {
2727
+ border: 1px solid #EAECF0;
2728
+ border-radius: 4px;
2729
+ margin-bottom: 16px;
2730
+ overflow: hidden;
2731
+
2732
+ .org-card-header {
2733
+ display: flex;
2734
+ justify-content: space-between;
2735
+ align-items: center;
2736
+ padding: 12px 16px;
2737
+ background-color: #f9fafb;
2738
+ border-bottom: 1px solid #EAECF0;
2739
+
2740
+ &:hover {
2741
+ background-color: #f3f4f6;
2742
+ }
2743
+
2744
+ .org-card-title {
2745
+ display: flex;
2746
+ align-items: center;
2747
+ font-weight: 500;
2748
+ cursor: pointer;
2749
+ }
2750
+
2751
+ .org-card-actions {
2752
+ display: flex;
2753
+ align-items: center;
2754
+ gap: 10px;
2755
+
2756
+ .ivu-btn-text {
2757
+ color: #1890ff;
2758
+ font-weight: 500;
2759
+ transition: all 0.2s;
2760
+ cursor: pointer;
2761
+
2762
+ &:hover {
2763
+ color: #40a9ff;
2764
+ text-decoration: underline;
2765
+ transform: translateY(-1px);
2766
+ }
2767
+
2768
+ &:active {
2769
+ color: #096dd9;
2770
+ transform: translateY(0);
2771
+ }
2772
+ }
2773
+ }
2774
+ }
2775
+
2776
+ .org-card-body {
2777
+ padding: 16px;
2778
+ }
2779
+ }
2780
+
2781
+ .city-card {
2782
+ border: 1px solid #EAECF0;
2783
+ border-radius: 4px;
2784
+ margin-bottom: 12px;
2785
+ overflow: hidden;
2786
+
2787
+ .city-card-header {
2788
+ display: flex;
2789
+ justify-content: space-between;
2790
+ align-items: center;
2791
+ padding: 10px 14px;
2792
+ background-color: #f9fafb;
2793
+ border-bottom: 1px solid #EAECF0;
2794
+
2795
+ &:hover {
2796
+ background-color: #f3f4f6;
2797
+ }
2798
+
2799
+ .city-card-title {
2800
+ display: flex;
2801
+ align-items: center;
2802
+ font-weight: 500;
2803
+ cursor: pointer;
2804
+ }
2805
+
2806
+ .city-card-actions {
2807
+ display: flex;
2808
+ align-items: center;
2809
+ gap: 10px;
2810
+
2811
+ .ivu-btn-text {
2812
+ color: #1890ff;
2813
+ font-weight: 500;
2814
+ transition: all 0.2s;
2815
+ cursor: pointer;
2816
+
2817
+ &:hover {
2818
+ color: #40a9ff;
2819
+ text-decoration: underline;
2820
+ transform: translateY(-1px);
2821
+ }
2822
+
2823
+ &:active {
2824
+ color: #096dd9;
2825
+ transform: translateY(0);
2826
+ }
2827
+ }
2828
+ }
2829
+ }
2830
+
2831
+ .city-card-body {
2832
+ padding: 14px;
2833
+ }
2834
+ }
2835
+
2836
+ .district-grid {
2837
+ display: grid;
2838
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
2839
+ gap: 12px;
2840
+ }
2841
+
2842
+ .district-item {
2843
+ border: 1px solid #EAECF0;
2844
+ border-radius: 4px;
2845
+ overflow: hidden;
2846
+
2847
+ .district-header {
2848
+ display: flex;
2849
+ justify-content: space-between;
2850
+ align-items: center;
2851
+ padding: 8px 12px;
2852
+ background-color: #f9fafb;
2853
+ border-bottom: 1px solid #EAECF0;
2854
+
2855
+ &:hover {
2856
+ background-color: #f3f4f6;
2857
+ }
2858
+
2859
+ .district-title {
2860
+ display: flex;
2861
+ align-items: center;
2862
+ font-weight: 500;
2863
+ cursor: pointer;
2864
+ }
2865
+
2866
+ .district-actions {
2867
+ display: flex;
2868
+ align-items: center;
2869
+ gap: 10px;
2870
+
2871
+ .ivu-btn-text {
2872
+ color: #1890ff;
2873
+ font-weight: 500;
2874
+ transition: all 0.2s;
2875
+ cursor: pointer;
2876
+
2877
+ &:hover {
2878
+ color: #40a9ff;
2879
+ text-decoration: underline;
2880
+ transform: translateY(-1px);
2881
+ }
2882
+
2883
+ &:active {
2884
+ color: #096dd9;
2885
+ transform: translateY(0);
2886
+ }
2887
+ }
2888
+ }
2889
+ }
2890
+
2891
+ .district-body {
2892
+ padding: 12px;
2893
+ }
2894
+ }
2895
+
2896
+ .org-unit-item {
2897
+ margin-bottom: 8px;
2898
+
2899
+ &:last-child {
2900
+ margin-bottom: 0;
2901
+ }
2902
+ }
2903
+
2904
+ .unit-title {
2905
+ display: flex;
2906
+ align-items: center;
2907
+ padding: 4px 0;
2908
+ cursor: pointer;
2909
+
2910
+ &:hover {
2911
+ color: #1890ff;
2912
+ }
2913
+ }
2914
+
2915
+ .org-card-title,
2916
+ .city-card-title,
2917
+ .district-title {
2918
+ cursor: pointer;
2919
+
2920
+ &:hover {
2921
+ color: #1890ff;
2922
+ }
2923
+ }
2924
+
2925
+ .org-new-footer {
2926
+ display: flex;
2927
+ justify-content: space-between;
2928
+ align-items: center;
2929
+ padding-top: 16px;
2930
+ border-top: 1px solid #f0f0f0;
2931
+ }
2932
+
2933
+ .include-level {
2934
+ display: flex;
2935
+ align-items: center;
2936
+ }
2937
+ }
2938
+
2290
2939
  .custom-select-wrapper {
2291
2940
  position: relative;
2292
2941