personnelSearch.vue 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <script lang="ts" setup>
  2. // import { ref, reactive, onMounted, inject, watchEffect, watch, computed } from 'vue';
  3. const props = defineProps({
  4. modelValue: { type: null, required: true },
  5. multiple: { type: Boolean, required: false, default: false },
  6. size: { type: String as () => '' | 'large' | 'default' | 'small', required: true, default: () => '' },
  7. placeholder: { type: String, required: false, default: () => '请选择' },
  8. disabled: { type: Boolean, required: false, default: false },
  9. options: { type: Array as () => optionsType, required: false, default: () => [] },
  10. clearable: { type: Boolean, required: false, default: true },
  11. width: { type: String, required: false, default: () => '100%' },
  12. url: { type: String, required: false, default: () => '' },
  13. });
  14. type optionsType = {
  15. label: string,
  16. value: string | number,
  17. jobNumber?: string,
  18. }[]
  19. interface Emits {
  20. (event: "change", value: any): void;
  21. /**
  22. * 双向绑定事件
  23. * @param value 对应数据
  24. */
  25. (event: "update:modelValue", value: any): void;
  26. }
  27. const emit = defineEmits<Emits>();
  28. const personnelArray = ref<optionsType>([]);
  29. const { userInfo = {}, personnelList = [] } = JSON.parse(sessionStorage.getItem('storeInfo') || '{}')
  30. const textSize = ref({
  31. 'small': { height: '20px', fontSize: '12px' },
  32. 'default': { height: '28px', fontSize: '14px' },
  33. '': { height: '28px', fontSize: '14px' },
  34. 'large': { height: '36px', fontSize: '14px' },
  35. })
  36. const selectLoading = ref(false);
  37. const controlTranslation = reactive({
  38. visibleFlag: false // 下拉框出现隐藏
  39. })
  40. const selectedValue = ref(props.modelValue); // 响应式绑定 v-model 的值
  41. watch(() => props.modelValue, (newValue, _oldValue) => {
  42. if(newValue != selectedValue.value) {
  43. selectedValue.value = newValue
  44. }
  45. });
  46. const getSelectedLabel = computed(() => {
  47. if (!props.multiple) {
  48. const item = getPersonnelListItems(selectedValue.value || props.modelValue);
  49. return item ? item.label : props.placeholder
  50. }
  51. if (props.multiple) {
  52. if (Array.isArray(selectedValue.value)) {
  53. if (selectedValue.value.length <= 0) {
  54. return props.placeholder
  55. }
  56. const item = getPersonnelListItems(selectedValue.value || props.modelValue);
  57. return item ? item.label : props.placeholder
  58. } else {
  59. return props.placeholder
  60. }
  61. }
  62. return props.placeholder
  63. })
  64. function tagClose(_evt: MouseEvent) {
  65. if (Array.isArray(selectedValue.value)) {
  66. selectedValue.value.shift()
  67. updateValue(selectedValue.value)
  68. }
  69. }
  70. function getPersonnelListItems(val: any) {
  71. let value = val;
  72. if (Array.isArray(val) && val.length > 0) {
  73. value = val[0]
  74. }
  75. return personnelList.find((item: any) => item.value == value)
  76. }
  77. function getUserList(keyword: string = '') {
  78. newPost(props.url, keyword).then(res => {
  79. personnelArray.value = (res || [])
  80. }).finally(() => {
  81. selectLoading.value = false
  82. })
  83. }
  84. function newPost(url: string, keyword: string): Promise<any> {
  85. return new Promise((resolve, reject) => {
  86. const token: any = sessionStorage.getItem('token');
  87. if (!token) {
  88. reject(new Error("Token is missing"));
  89. return;
  90. }
  91. const body = new URLSearchParams();
  92. body.append('keyword', keyword);
  93. fetch(url, {
  94. method: "POST", // 确保请求方法正确,如果是其他方法需要修改
  95. headers: {
  96. "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
  97. "Token": token
  98. },
  99. body: body.toString()
  100. })
  101. .then(resp => {
  102. if (!resp.ok) {
  103. reject(new Error(`Error: ${resp.statusText}`));
  104. }
  105. return resp.json();
  106. })
  107. .then((json) => {
  108. const res = json.data;
  109. if (Array.isArray(res)) {
  110. const personnelArray = res.map(data => ({
  111. label: data['label'],
  112. value: data['value'],
  113. }));
  114. resolve(personnelArray);
  115. } else {
  116. reject(new Error("Invalid data format"));
  117. }
  118. })
  119. .catch((error) => {
  120. reject(error);
  121. });
  122. });
  123. }
  124. function visibleChange(visible: boolean) { // 下拉框出现/隐藏时触发
  125. if(visible) {
  126. personnelArray.value = personnelList
  127. }
  128. controlTranslation.visibleFlag = visible
  129. }
  130. const filterMethod = debounce(filterMethods, 500)
  131. function filterMethods(val: string) {
  132. if (val == '') {
  133. personnelArray.value = personnelList
  134. selectLoading.value = false
  135. return personnelArray.value
  136. }
  137. selectLoading.value = true
  138. getUserList(val)
  139. }
  140. function updateValue(val: any) { // 值改变的时候触发
  141. emit('update:modelValue', selectedValue.value)
  142. emit('change', val)
  143. }
  144. function debounce(func: Function, delay: number) {
  145. let timer: any;
  146. return (...args: any[]) => {
  147. if (timer) {
  148. clearTimeout(timer);
  149. }
  150. timer = setTimeout(() => {
  151. func(...args);
  152. }, delay);
  153. };
  154. }
  155. onMounted(() => {
  156. if (personnelList.length == 0) {
  157. getUserList()
  158. } else {
  159. personnelArray.value = personnelList
  160. }
  161. })
  162. </script>
  163. <template>
  164. <!-- <el-select-v2 v-model="selectedValue" :multiple="multiple" :size="size"
  165. :loading="selectLoading" :placeholder="placeholder" :disabled="disabled" :clearable="clearable" filterable collapse-tags :options="(personnelArray || [])"
  166. :style="`width: ${width}`" :class="`custom-select-v2-reset ${!controlTranslation.visibleFlag ? 'setUpInputReset' : ''}`"
  167. @change="updateValue"
  168. @visible-change="visibleChange" :filter-method="filterMethod">
  169. <template #prefix v-if="!multiple">
  170. <div class="selectV2SingleChoiceReset">
  171. <div v-if="!controlTranslation.visibleFlag" class="selectSingleChoice" :style="`line-height: ${textSize[size].height};font-size:${textSize[size].fontSize}`">
  172. <template v-if="getSelectedLabel == placeholder">
  173. <span style="color: #A8ABB2">{{ placeholder }}</span>
  174. </template>
  175. <template v-else>
  176. <span style="color: #606266;">
  177. {{ getSelectedLabel }}
  178. </span>
  179. </template>
  180. </div>
  181. </div>
  182. </template>
  183. <template #prefix v-if="multiple">
  184. <div class="selectV2SingleChoiceTwoReset">
  185. <div class="selectSingleChoice" :style="`line-height: ${textSize[size].height};font-size:${textSize[size].fontSize}`">
  186. <template v-if="getSelectedLabel == placeholder">
  187. <span style="color: #A8ABB2">{{ placeholder }}</span>
  188. </template>
  189. <template v-else>
  190. <el-tag type="info" :size="size" closable @close="tagClose" style="margin-right: 5px;">
  191. {{ getSelectedLabel }}
  192. </el-tag>
  193. <el-tag type="info" :size="size" v-if="selectedValue.length > 1">+{{ selectedValue.length }}</el-tag>
  194. </template>
  195. </div>
  196. </div>
  197. </template>
  198. <template #default="{ item }">
  199. <div class="flex items-center">
  200. {{ item.label }}
  201. </div>
  202. </template>
  203. </el-select-v2> -->
  204. <el-select v-model="selectedValue" :multiple="multiple" :size="size"
  205. :loading="selectLoading" :placeholder="placeholder" :disabled="disabled" :clearable="clearable" filterable collapse-tags
  206. :style="`width: ${width}`" :class="`custom-select-v2-reset ${!controlTranslation.visibleFlag ? 'setUpInputReset' : ''}`"
  207. @change="updateValue"
  208. @visible-change="visibleChange" :filter-method="filterMethod">
  209. <template #prefix v-if="!multiple">
  210. <div class="selectV2SingleChoiceReset">
  211. <div v-if="!controlTranslation.visibleFlag" class="selectSingleChoice" :style="`line-height: ${textSize[size].height};font-size:${textSize[size].fontSize}`">
  212. <template v-if="getSelectedLabel == placeholder">
  213. <span style="color: #A8ABB2">{{ placeholder }}</span>
  214. </template>
  215. <template v-else>
  216. <span style="color: #606266;">
  217. <!-- {{ getSelectedLabel }} -->
  218. <ww-open-data type='userName' :openid='getSelectedLabel'></ww-open-data>
  219. </span>
  220. </template>
  221. </div>
  222. </div>
  223. </template>
  224. <template #prefix v-if="multiple">
  225. <div class="selectV2SingleChoiceTwoReset">
  226. <div class="selectSingleChoice" :style="`line-height: ${textSize[size].height};font-size:${textSize[size].fontSize}`">
  227. <template v-if="getSelectedLabel == placeholder">
  228. <span style="color: #A8ABB2">{{ placeholder }}</span>
  229. </template>
  230. <template v-else>
  231. <el-tag type="info" :size="size" closable @close="tagClose" style="margin-right: 5px;">
  232. <!-- {{ getSelectedLabel }} -->
  233. <ww-open-data type='userName' :openid='getSelectedLabel'></ww-open-data>
  234. </el-tag>
  235. <el-tag type="info" :size="size" v-if="selectedValue.length > 1">+{{ selectedValue.length }}</el-tag>
  236. </template>
  237. </div>
  238. </div>
  239. </template>
  240. <el-option
  241. v-for="item in (personnelArray || [])"
  242. :key="item.value"
  243. :label="item.label"
  244. :value="item.value"
  245. >
  246. <span style="float: left">
  247. <ww-open-data type='userName' :openid='item.label'></ww-open-data>
  248. <!-- {{ item.label }} -->
  249. </span>
  250. </el-option>
  251. </el-select>
  252. </template>
  253. reset
  254. <style lang="scss">
  255. .custom-select-v2-reset {
  256. position: relative;
  257. .selectV2SingleChoiceReset, .selectV2SingleChoiceTwoReset {
  258. position: absolute;
  259. display: flex;
  260. align-items: center;
  261. transform: translate(0,-50%);
  262. .selectSingleChoice {
  263. background: #fff;
  264. }
  265. }
  266. .el-select-v2__placeholder {
  267. display: none !important;
  268. }
  269. .el-select-v2__selected-item {
  270. .el-tag {
  271. display: none !important;
  272. }
  273. }
  274. .selectV2SingleChoiceReset {
  275. top: 50%;
  276. left: 14px;
  277. }
  278. .selectV2SingleChoiceTwoReset {
  279. position: relative;
  280. transform: translate(0);
  281. }
  282. .el-input__inner::placeholder {
  283. color: transparent !important;
  284. }
  285. .el-select__tags {
  286. .el-tag {
  287. display: none !important;
  288. }
  289. }
  290. .el-select-tags-wrapper {
  291. width: 110px !important;
  292. }
  293. }
  294. .setUpInputReset .el-input__inner {
  295. color: #fff !important;
  296. }
  297. </style>