Browse Source

增加js配置及文件

master
zq 1 week ago
parent
commit
88222f5a31
  1. 10
      build/webpack.config.js
  2. 15478
      examples/package-lock.json
  3. 12
      examples/package.json
  4. 114
      examples/src/App.vue
  5. 14843
      package-lock.json
  6. 9
      package.json
  7. 7
      packages/CustomDropdown/index.js
  8. 271
      packages/CustomDropdown/src/index copy.vue
  9. 328
      packages/CustomDropdown/src/index.vue
  10. 7
      packages/GuipFormItem/index.js
  11. 52
      packages/GuipFormItem/src/index.vue
  12. 7
      packages/GuipSelect/index.js
  13. 111
      packages/GuipSelect/src/index.vue
  14. 1
      packages/assets/drop-selected.svg
  15. BIN
      packages/assets/dropDown_expand.png
  16. BIN
      packages/assets/dropDown_open.png
  17. 26
      packages/index.js
  18. 75
      packages/utils/clipboard.js
  19. 32
      packages/utils/common.js
  20. 19
      packages/utils/dirClipBoard.js
  21. 11
      packages/utils/eventBus.js
  22. 17
      packages/utils/headerIcon.js
  23. 93
      packages/utils/request.js

10
build/webpack.config.js

@ -70,6 +70,16 @@ module.exports = {
publicPath: '../'
}
}]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},

15478
examples/package-lock.json

File diff suppressed because it is too large

12
examples/package.json

@ -10,22 +10,22 @@
},
"dependencies": {
"core-js": "^3.8.3",
"element-ui": "^2.15.13",
"my-components": "file:../",
"vue": "^2.6.14",
"element-ui": "^2.15.13",
"vue-loader": "^17.4.2"
"vue-loader": "^15.9.8"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.5.19",
"@vue/cli-plugin-eslint": "^4.5.19",
"@vue/cli-service": "^4.5.19",
"sass": "^1.89.2",
"babel-eslint": "^10.1.0",
"sass-loader": "^10.2.0",
"vue-template-compiler": "^2.6.14",
"css-loader": "^5.2.7",
"eslint": "^6.8.0",
"eslint-plugin-vue": "^6.2.2"
"sass": "^1.32.13",
"sass-loader": "^8.0.2",
"eslint-plugin-vue": "^6.2.2",
"vue-template-compiler": "^2.6.14"
},
"browserslist": [
"> 1%",

114
examples/src/App.vue

@ -124,7 +124,7 @@
</template>
</DevicePreview>
</section>
<section>
<section class="demo-section">
<h2>单选框组件集合</h2>
<div class="ele-item">
<label for="">单选框(对象格式)</label>
@ -151,6 +151,111 @@
</el-radio-group>
</div>
</section>
<section class="demo-section">
<h2>下拉组件集合</h2>
<!-- <div class="flex ele-item">
<label for="">普通下拉选择框可自定义属性</label>
<GuipSelect width="600px" v-model="form.card" clearable label="卡片" :default-value="form.card" prop="card"
:options="options" valueKey="id1" labelKey="id2" />
</div> -->
<!-- <div class="flex ele-item">
<label for="">inputdrop组合使用(默认使用)</label>
<GuipFormItem column="column" class="combo-formItem w510" label="域名设置" required="true">
<div slot="formDom" class="self-drop-wrap flex">
<GuipInput style="width: 60%;" v-model="form.domain_set" placeholder="仅支持数字、字母">
</GuipInput>
<div @click="toggleDrop" class="point flex appendDrop" style="width: 40%;">
{{ currentDomainItem.name }}</div>
</div>
<CustomDropdown slot="formDom" ref="dropDomain" width="100%" v-model="form.domainSuffix1"
:options="domainOptions" @change="changeSelectIp" placeholder="请选择">
<template #normal>
<div class="flex flex-between noraml-jump">
<div class="left">
<b>添加新域名</b>
<p class="one ft12">域名需要在阿里云完成ICP备案并解析到平台服务器</p>
<p class="ft12">如果暂时未准备好可先选用平台免费域名随时支持域名修改 </p>
</div>
<div class="right">
<GuipButton size="form">前往绑定</GuipButton>
</div>
</div>
</template>
</CustomDropdown>
</GuipFormItem>
</div> -->
<!-- <div class="flex ele-item">
<label for="">inputdrop组合使用(自定义下拉选择项)</label>
<GuipFormItem column="column" class="combo-formItem w510" label="域名设置" required="true">
<div slot="formDom" class="self-drop-wrap flex">
<GuipInput style="width: 60%;" v-model="form.domain_set" placeholder="仅支持数字、字母">
</GuipInput>
<div @click="toggleDrop1" class="point flex appendDrop" style="width: 40%;">
{{ currentDomainItem.name }}
</div>
</div>
<CustomDropdown slot="formDom" ref="dropDomain1" width="100%" v-model="form.domainSuffix"
:options="domainOptions" @change="changeSelectIp" valueKey="id" placeholder="请选择">
<template #normal>
<div class="flex flex-between noraml-jump">
<div class="left">
<b>添加新域名</b>
<p class="one ft12">域名需要在阿里云完成ICP备案并解析到平台服务器</p>
<p class="ft12">如果暂时未准备好可先选用平台免费域名随时支持域名修改 </p>
</div>
<div class="right">
<GuipButton size="form">前往绑定</GuipButton>
</div>
</div>
</template>
<template #item="{ item }">
<div class="flex-between">
<div class="left">
<p class="one">{{ item.label }}</p>
</div>
<div class="right">
<img v-if="form.domainSuffix == item.id" src="~@assets/drop-selected.svg" alt="">
</div>
</div>
</template>
</CustomDropdown>
</GuipFormItem>
</div> -->
<div class="flex ele-item">
<label for="">单独实现自定义内容下拉选择</label>
<!-- <CustomDropdown width="500px"
v-model="selectedValue"
:options="options"
:null-option="nullOption"
@change="handleSafeChange"
@opened="onOpen"
@closed="onClose"
> -->
<CustomDropdown width="500px" v-model="form.domainSuffix" :options="domainOptions" @change="changeSelectIp"
valueKey="id" placeholder="请选择" @opened="onOpen"
@closed="onClose">
<template #normal>
<div class="flex flex-between noraml-jump">
<div class="left">
<b>添加新域名</b>
<p class="one ft12">域名需要在阿里云完成ICP备案并解析到平台服务器</p>
<p class="ft12">如果暂时未准备好可先选用平台免费域名随时支持域名修改 </p>
</div>
<div class="right">
<GuipButton size="form">前往绑定</GuipButton>
</div>
</div>
</template>
<template #item="{ item }">
<div class="flex-between">
<p>测试一下自定义内容{{ item.id }} + {{ item.label }}</p>
<p>易烊千玺/田栩宁</p>
</div>
</template>
</CustomDropdown>
</div>
</section>
</el-form>
@ -522,10 +627,17 @@ export default {
console.log(e, '---000changeInputtest');
},
changeSelectIp(item) {
//
// this.selectedItem1 = { ...item };
console.log(item, this.form.domainSuffix, this.form.domainSuffix1, '选中的项-值-');
},
onOpen() {
console.log('下拉框打开')
},
onClose() {
console.log('下拉框关闭')
},
arraySpanMethod({ row, column, rowIndex, columnIndex }) {
console.log(row, column);
if (rowIndex % 2 === 0) {

14843
package-lock.json

File diff suppressed because it is too large

9
package.json

@ -23,7 +23,11 @@
"release": "npm version patch && npm publish"
},
"devDependencies": {
"@babel/core": "^7.16.0",
"@babel/plugin-transform-runtime": "^7.16.0",
"@babel/preset-env": "^7.16.0",
"babel-eslint": "~10.1.0",
"babel-loader": "^8.2.5",
"css-loader": "~5.2.7",
"eslint": "~6.8.0",
"eslint-plugin-vue": "~6.2.2",
@ -59,5 +63,8 @@
"component-library",
"ui-components"
],
"license": "MIT"
"license": "MIT",
"dependencies": {
"vue-clickaway": "^2.2.2"
}
}

7
packages/CustomDropdown/index.js

@ -0,0 +1,7 @@
import CustomDropdown from './src/index.vue'
CustomDropdown.install = function(Vue) {
Vue.component(CustomDropdown.name || 'CustomDropdown', CustomDropdown)
}
export default CustomDropdown

271
packages/CustomDropdown/src/index copy.vue

@ -0,0 +1,271 @@
<template>
<div class="custom-select" v-clickaway="closeDropdown" ref="dropdown" :class="{ 'is-open': isOpen }"
:style="{ width }">
<!-- 触发按钮 -->
<div class="select-trigger" @click="toggleDropdown">
<slot name="trigger">
{{ localSelected ? localSelected[displayKey] : placeholder }}
</slot>
<img class="arrow-icon"
:src="isOpen ? require('../../assets/dropDown_open.png') : require('../../assets/dropDown_expand.png')"
alt="">
</div>
<!-- 下拉内容 -->
<transition name="slide-fade">
<div v-if="isOpen" class="select-dropdown">
<slot v-if="isOpen" name="normal"></slot>
<div v-if="options">
<div v-for="(item, index) in options" :key="index" class="dropdown-item "
:class="{ 'is-selected': isSelected(item) }" @click="selectItem(item)">
<slot name="item" :item="item">
<div class="flex-between">
<div class="left">
<p class="one">{{ item[displayKey] }}</p>
</div>
<div class="right">
<img v-if="localSelected[displayKey] == item[displayKey]"
src="../../assets/drop-selected.svg" alt="">
</div>
</div>
</slot>
</div>
</div>
<div class="flex-between dropdown-item" v-if="options_null" @click="selectNullItem">
<div class="left">
<p class="one">暂无收款账号</p>
<p>暂时没有收款账号我想稍后配置</p>
</div>
<div class="right">
<img src="../../assets/drop-selected.svg" alt="">
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
import { $emit, $on, $off } from '../../utils/eventBus'
export default {
name: 'CustomDropdown',
props: {
width: {
type: String,
default: "200px",
},
options: {
type: Array,
default: () => [],
},
options_null: {
type: Object,
default: () => { },
},
placeholder: {
type: String,
default: "请选择",
},
value: {
type: [String, Number, Object],
default: null,
},
valueKey: {
type: String,
default: "value",
},
displayKey: {
type: String,
default: "label",
},
},
data() {
return {
isOpen: false,
localSelected: null, //
isUpdating: false //
// selectedItem: null,
};
},
watch: {
value: {
immediate: true,
handler(val) {
//
if (!this.localSelected || this.localSelected[this.valueKey] !== val) {
this.localSelected = this.options.find(item => item[this.valueKey] === val);
}
}
}
},
computed: {
// selectedItem: {
// get() {
// // props
// return this.options.find(item => item[this.valueKey] === this.value) || null;
// },
// set(newVal) {
// //
// this.$emit('input', newVal ? newVal[this.valueKey] : null);
// this.$emit('change', newVal);
// }
// }
// selectedItem: {
// get() {
// if (this.isUpdating) return this._selectedItem;
// return this.options.find(item => item[this.valueKey] === this.value) || null;
// },
// set(newVal) {
// this.isUpdating = true;
// this._selectedItem = newVal;
// this.$nextTick(() => {
// this.$emit('input', newVal ? newVal[this.valueKey] : null);
// this.isUpdating = false;
// });
// }
// }
},
// data selectedItem watch
created() {
//
$on('close-all-dropdowns', this.closeDropdown)
},
beforeDestroy() {
//
$off('close-all-dropdowns', this.closeDropdown)
},
methods: {
closeDropdown() {
this.isOpen = false;
},
toggleDropdown(e) {
if (e) {
e.stopPropagation();
}
//
$emit('close-all-dropdowns')
this.isOpen = !this.isOpen;
},
// selectItem(item) {
// this.selectedItem = item;
// this.$emit("input", item[this.valueKey]); // Use the specified valueKey
// this.$emit("change", item);
// this.isOpen = false;
// },
// selectItem(item) {
// //
// this.$emit("input", item[this.valueKey]);
// this.$emit("change", item);
// //
// this.$nextTick(() => {
// this.selectedItem = item;
// this.isOpen = false;
// });
// },
selectItem(item) {
this.localSelected = item;
this.$emit('input', item[this.valueKey]);
this.$emit('change', item);
this.isOpen = false;
},
// selectItem(item) {
// this.selectedItem = item; // computed setter
// // this.$emit("change", item);
// this.isOpen = false;
// },
isSelected(item) {
return this.localSelected && this.localSelected[this.valueKey] === item[this.valueKey];
},
selectNullItem() {
this.$emit("changeNormal", '');
this.isOpen = false;
}
},
};
</script>
<style scoped>
/* Your existing styles remain the same */
.custom-select {
display: inline-block;
vertical-align: middle;
height: 38px;
position: relative;
font-family: Arial, sans-serif;
}
.select-trigger {
border-radius: 2px;
opacity: 1;
background: #FFFFFF;
border: 1px solid #DFE2E6;
width: 100%;
height: 40px;
box-sizing: border-box;
padding: 10px 12px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
.is-open .select-trigger {
border: 1px solid #006AFF;
transition: all .5s;
outline: 3px solid #D8E9FA;
}
.select-trigger:hover {
border-color: #006AFF;
transition: all .5s;
}
.arrow-icon {
width: 12px;
}
.select-dropdown {
position: absolute;
top: 100%;
right: 0;
width: 100%;
border: 1px solid #ccc;
box-sizing: border-box;
border-radius: 4px;
background-color: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
z-index: 1000;
margin-top: 4px;
max-height: 384px;
overflow-y: auto;
padding: 0 12px 12px 12px;
}
.dropdown-item {
padding: 12px 10px;
cursor: pointer;
}
.dropdown-item:hover {
background: #F6F7FA;
}
.dropdown-item.is-selected {
background-color: #F6F7FA;
color: #006AFF;
}
/* 展开收起动画 */
.slide-fade-enter-active,
.slide-fade-leave-active {
transition: all 0.3s ease;
}
.slide-fade-enter-from,
.slide-fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
</style>

328
packages/CustomDropdown/src/index.vue

@ -0,0 +1,328 @@
<template>
<div class="custom-select"
v-clickaway="handleClickAway"
ref="dropdown"
:class="{ 'is-open': state.isOpen }"
:style="{ width: computedWidth }">
<!-- 触发按钮 -->
<div class="select-trigger" @click.stop="toggleDropdown">
<slot name="trigger">
{{ displayText }}
</slot>
<img class="arrow-icon"
:src="state.isOpen ? openIcon : expandIcon"
alt="dropdown indicator">
</div>
<!-- 下拉内容 -->
<transition name="slide-fade">
<div v-show="state.isOpen" class="select-dropdown">
<slot v-if="state.isOpen" name="normal"></slot>
<template v-if="filteredOptions.length">
<div v-for="(item, index) in filteredOptions"
:key="`option-${index}`"
class="dropdown-item"
:class="{ 'is-selected': isSelected(item) }"
@click.stop="selectItem(item)">
<slot name="item" :item="item">
<div class="flex-between">
<div class="left">
<p class="one">{{ item[displayKey] }}</p>
</div>
<div class="right">
<img v-if="isSelected(item)"
:src="selectedIcon"
alt="selected">
</div>
</div>
</slot>
</div>
</template>
<div v-if="showNullOption"
class="flex-between dropdown-item"
@click.stop="selectNullItem">
<div class="left">
<p class="one">暂无收款账号</p>
<p>暂时没有收款账号我想稍后配置</p>
</div>
<div class="right">
<img :src="selectedIcon" alt="selected">
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
// Webpack
const STATIC_ICONS = Object.freeze({
expand: require('../../assets/dropDown_expand.png'),
open: require('../../assets/dropDown_open.png'),
selected: require('../../assets/drop-selected.svg')
})
export default {
name: 'CustomDropdown',
props: {
width: {
type: String,
default: "200px",
validator: (val) => /^\d+(px|%|rem|em|vw)$/.test(val)
},
options: {
type: Array,
default: () => [],
validator: (arr) => !arr.some(item => item === null || typeof item !== 'object')
},
nullOption: {
type: Object,
default: null
},
placeholder: {
type: String,
default: "请选择"
},
value: {
type: [String, Number, Object],
default: null
},
valueKey: {
type: String,
default: "value",
validator: (key) => typeof key === 'string' && key.trim().length > 0
},
displayKey: {
type: String,
default: "label",
validator: (key) => typeof key === 'string' && key.trim().length > 0
}
},
// 使
data: () => ({
state: Object.seal({
isOpen: false,
lastEmittedValue: null,
updateDepth: 0,
eventLock: false
}),
icons: STATIC_ICONS
}),
computed: {
computedWidth() {
return this.width.endsWith('px') ? this.width : `${parseInt(this.width)}px`
},
filteredOptions() {
return Array.isArray(this.options) ? [...this.options] : []
},
showNullOption() {
return this.nullOption && !this.filteredOptions.length
},
displayText() {
const current = this.findOptionByValue(this.value)
return current ? current[this.displayKey] : this.placeholder
},
openIcon() {
return this.icons.open
},
expandIcon() {
return this.icons.expand
},
selectedIcon() {
return this.icons.selected
}
},
watch: {
value: {
immediate: true,
handler(newVal) {
if (this.state.eventLock) return
this.state.lastEmittedValue = JSON.stringify(newVal)
}
}
},
methods: {
//
findOptionByValue(value) {
if (value === null || value === undefined) return null
return this.filteredOptions.find(item => {
return JSON.stringify(item[this.valueKey]) === JSON.stringify(value)
})
},
isSelected(item) {
if (!this.value) return false
return JSON.stringify(item[this.valueKey]) === JSON.stringify(this.value)
},
//
handleClickAway() {
if (!this.state.isOpen) return
this.state.isOpen = false
this.$nextTick(() => {
this.$emit('closed')
})
},
//
toggleDropdown() {
if (this.state.eventLock) return
if (this.state.isOpen) {
this.handleClickAway()
} else {
this.$emit('opened')
this.state.isOpen = true
}
},
//
selectItem(item) {
if (this.state.updateDepth > 1) {
console.error('Recursion detected in dropdown selection')
this.state.isOpen = false
this.state.updateDepth = 0
return
}
const newValue = item[this.valueKey]
//
if (this.state.lastEmittedValue === JSON.stringify(newValue)) {
this.state.isOpen = false
return
}
this.state.updateDepth++
this.state.eventLock = true
this.state.lastEmittedValue = JSON.stringify(newValue)
// 使setTimeout
setTimeout(() => {
try {
this.$emit('input', newValue)
this.$emit('change', Object.freeze({ ...item }))
} catch (e) {
console.error('Dropdown emit error:', e)
} finally {
this.state.isOpen = false
this.state.updateDepth = 0
this.state.eventLock = false
}
}, 0)
},
selectNullItem() {
this.state.eventLock = true
this.state.lastEmittedValue = null
setTimeout(() => {
this.$emit('input', null)
this.$emit('change', null)
this.state.isOpen = false
this.state.eventLock = false
}, 0)
}
},
//
created() {
this.$_performanceMark = `dropdown-${Date.now()}`
performance.mark(this.$_performanceMark)
},
beforeDestroy() {
performance.measure('dropdown-lifetime', this.$_performanceMark)
}
}
</script>
<style scoped lang="scss">
/* Your existing styles remain the same */
.custom-select {
display: inline-block;
vertical-align: middle;
height: 38px;
position: relative;
font-family: Arial, sans-serif;
}
.select-trigger {
border-radius: 2px;
opacity: 1;
background: #FFFFFF;
border: 1px solid #DFE2E6;
width: 100%;
height: 40px;
box-sizing: border-box;
padding: 10px 12px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
.is-open .select-trigger {
border: 1px solid #006AFF;
transition: all .5s;
outline: 3px solid #D8E9FA;
}
.select-trigger:hover {
border-color: #006AFF;
transition: all .5s;
}
.arrow-icon {
width: 12px;
}
.select-dropdown {
position: absolute;
top: 100%;
right: 0;
width: 100%;
border: 1px solid #ccc;
box-sizing: border-box;
border-radius: 4px;
background-color: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
z-index: 1000;
margin-top: 4px;
max-height: 384px;
overflow-y: auto;
padding: 0 12px 12px 12px;
}
.dropdown-item {
padding: 12px 10px;
cursor: pointer;
}
.dropdown-item:hover {
background: #F6F7FA;
}
.dropdown-item.is-selected {
background-color: #F6F7FA;
color: #006AFF;
}
/* 展开收起动画 */
.slide-fade-enter-active,
.slide-fade-leave-active {
transition: all 0.3s ease;
}
.slide-fade-enter-from,
.slide-fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
</style>

7
packages/GuipFormItem/index.js

@ -0,0 +1,7 @@
import GuipFormItem from './src/index.vue'
GuipFormItem.install = function(Vue) {
Vue.component(GuipFormItem.name || 'GuipFormItem', GuipFormItem)
}
export default GuipFormItem

52
packages/GuipFormItem/src/index.vue

@ -0,0 +1,52 @@
<template>
<div
:class="[{'column':column},{'error':hasError},{'w510':addClass=='w510'},{'w388':addClass=='w388'},'form-item1']">
<div class="form-item-top">
<label v-if="label" for="">{{ label }}
<img src="../../assets/require.svg" v-if="required" alt="">
</label>
<template >
<slot name="formLeft"></slot>
</template>
<template >
<slot name="formRight"></slot>
</template>
</div>
<div class="form-item-bottom">
<template >
<slot name="formDom"></slot>
</template>
</div>
</div>
</template>
<script>
export default {
name: 'GuipFormItem',
props:['label','required','addClass','column'],
data() {
return {
hasError: false,
//
classList:{
'w510':'w510',
'w388':'w388'
}
}
},
computed: {
// dynamicClasses() {
// return {
// active: this.isActive, // isActivetrue'active'
// error: this.hasError, // hasErrortrue'error'
// highlighted: this.isHighlighted, // isHighlightedtrue'highlighted'
// };
// }
},
mounted(){
// console.log(this.required,'required----');
}
}
</script>
<style lang="scss" scoped>
</style>

7
packages/GuipSelect/index.js

@ -0,0 +1,7 @@
import GuipSelect from './src/index.vue'
GuipSelect.install = function(Vue) {
Vue.component(GuipSelect.name || 'GuipSelect', GuipSelect)
}
export default GuipSelect

111
packages/GuipSelect/src/index.vue

@ -0,0 +1,111 @@
<template>
<el-form-item :style="{ ...style, height: height, ...styleObject }" :required="required"
:class="[{ 'column': column }, { 'w510': addClass == 'w510' }, { 'w388': addClass == 'w388' }, 'form-item']"
:label="label" :prop="prop" :rules="rules">
<p v-if="desc" class="desc_right">{{ desc }}</p>
<el-select :style="{ width: width }" :placeholder="placeholder1" @change="handleChange" v-model="selectedValue"
v-bind="$attrs">
<el-option v-for="item in processedOptions" :key="getItemValue(item)" :label="getItemLabel(item)"
:disabled="item.disabled" :value="getItemValue(item)">
</el-option>
</el-select>
</el-form-item>
</template>
<script>
export default {
name: 'GuipSelect',
props: {
value: [String, Number, Array],
options: {
type: Array,
default: () => []
},
//
valueKey: {
type: String,
default: 'value'
},
labelKey: {
type: String,
default: 'label'
},
styleObject: Object,
disabled: Boolean,
required: Boolean,
defaultValue: [String, Number, Array],
placeholder: String,
width: String,
height: String,
label: String,
type: String,
prop: String,
rules: [Object, Array],
column: Boolean,
addClass: String,
desc: String
},
data() {
return {
selectedValue: '',
style: {},
placeholder1: '请选择',
}
},
computed: {
// options
processedOptions() {
return this.options || []
}
},
watch: {
value(newVal) {
this.selectedValue = newVal
},
defaultValue(newVal) {
if (newVal !== undefined && newVal !== null) {
this.selectedValue = newVal
}
}
},
mounted() {
//
if (this.defaultValue !== undefined && this.defaultValue !== null) {
this.selectedValue = this.defaultValue
}
if (this.value !== undefined && this.value !== null) {
this.selectedValue = this.value
}
//
if (this.placeholder) {
this.placeholder1 = this.placeholder
}
this.$nextTick(() => {
let els = document.querySelectorAll('.el-input');
els.forEach(item => {
item.onmouseover = function () {
item.classList.add("hoverclass")
}
item.onmouseout = function () {
item.classList.remove("hoverclass")
}
})
})
},
methods: {
// value
getItemValue(item) {
return item[this.valueKey]
},
// label
getItemLabel(item) {
return item[this.labelKey]
},
handleChange(value) {
this.$emit('input', value)
this.$emit('change', value)
}
}
}
</script>

1
packages/assets/drop-selected.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="16" height="16" viewBox="0 0 16 16"><g><g></g><g><path d="M13.5732,5.315390953125Q13.6985,5.197082953125,13.7668,5.0388329531250005Q13.835,4.880582953125,13.835,4.708251953125Q13.835,4.626011653125,13.819,4.545351953125Q13.8029,4.464691953125,13.7714,4.388710953125Q13.74,4.3127309531249995,13.6943,4.244350953125Q13.6486,4.175970953125,13.5904,4.117817953125Q13.5323,4.059664953125,13.4639,4.013974953125Q13.3955,3.968284953125,13.3195,3.936812953125Q13.2436,3.905340953125,13.1629,3.889295953125Q13.0822,3.873251953125,13,3.873251953125Q12.90746,3.873251953125,12.81716,3.8935169531250002Q12.72686,3.913781953125,12.64319,3.953328953125Q12.55951,3.992875953125,12.48654,4.049783953125Q12.41356,4.106692953125,12.35481,4.178200953125L7.06803,9.842611953125001L3.542182,7.198221953125Q3.428807,7.101421953125,3.288942,7.049841953125Q3.149076,6.998251953125,3,6.998251953125Q2.9177597,6.998251953125,2.8371,7.014291953124999Q2.75644,7.030341953125,2.680459,7.061811953125Q2.604479,7.093281953125,2.536099,7.138971953125Q2.4677189999999998,7.184661953125,2.409566,7.242821953125Q2.351413,7.300971953125,2.305723,7.369351953124999Q2.260033,7.437731953125001,2.228561,7.513711953125Q2.197089,7.589691953125,2.181044,7.6703519531249995Q2.165,7.7510119531249995,2.165,7.833251953125Q2.165,7.937161953125,2.190469,8.037911953125Q2.215938,8.138651953125,2.265322,8.230081953125Q2.314706,8.321511953125,2.384993,8.398041953125Q2.45528,8.474581953125,2.542182,8.531551953125L6.66667,11.624921953125Q6.72781,11.670781953125001,6.796279999999999,11.704751953125001Q6.864739999999999,11.738721953125001,6.93825,11.759671953125Q7.01175,11.780621953125,7.08784,11.787851953125Q7.16393,11.795081953124999,7.24006,11.788351953125Q7.31619,11.781621953125,7.38983,11.761151953125001Q7.46347,11.740681953125,7.53216,11.707161953125Q7.60084,11.673641953125,7.66229,11.628181953125Q7.72373,11.582721953124999,7.77588,11.526851953125L13.5732,5.315390953125Z" fill-rule="evenodd" fill="#006AFF" fill-opacity="1"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
packages/assets/dropDown_expand.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
packages/assets/dropDown_open.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

26
packages/index.js

@ -1,3 +1,9 @@
import EventBus, {
$on,
$once,
$off,
$emit
} from './utils/eventBus'
import GuipButton from './GuipButton'
import GroupFormBtns from './GroupFormBtns'
import GuipInput from './GuipInput'
@ -5,10 +11,13 @@ import PromptText from './PromptText'
import GuipTextarea from './GuipTextarea'
import DevicePreview from './DevicePreview'
import GuipRadio from './GuipRadio'
import GuipSelect from './GuipSelect'
import GuipFormItem from './GuipFormItem'
import CustomDropdown from './CustomDropdown'
import 'element-ui/lib/theme-chalk/index.css' // 如果依赖Element
import './styles/index.css' // 全局引入
import './styles/common.scss' // 全局引入
import { directive as clickaway } from 'vue-clickaway'
const components = [
GuipButton,
GroupFormBtns,
@ -16,10 +25,18 @@ const components = [
PromptText,
GuipTextarea,
DevicePreview,
GuipRadio
GuipRadio,
GuipSelect,
GuipFormItem,
CustomDropdown
]
const install = function (Vue) {
// 挂载到Vue原型
Vue.prototype.$eventBus = EventBus
Vue.prototype.$on = $on
Vue.prototype.$emit = $emit
Vue.directive('clickaway', clickaway)
components.forEach(component => {
if (!component.name) {
throw new Error(`Component name is required: ${component}`)
@ -36,5 +53,8 @@ export default {
PromptText,
GuipTextarea,
DevicePreview,
GuipRadio
GuipRadio,
GuipSelect,
GuipFormItem,
CustomDropdown
}

75
packages/utils/clipboard.js

@ -0,0 +1,75 @@
/**
* 复制文本到剪贴板
* @param {string} text 要复制的文本
* @param {Object} options 配置选项
* @param {string} options.successMsg 成功提示信息
* @param {string} options.errorMsg 失败提示信息
* @param {Vue} options.vm Vue实例(用于调用$message)
* @returns {Promise<boolean>} 是否复制成功
*/
export function copyToClipboard(text, options = {}) {
const {
successMsg = '复制成功',
errorMsg = '复制失败,请手动复制',
vm = null
} = options;
return new Promise((resolve) => {
// 创建textarea元素
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed'; // 防止页面滚动
document.body.appendChild(textarea);
textarea.select();
try {
// 执行复制命令
const successful = document.execCommand('copy');
if (successful) {
if (vm && vm.$Message) {
vm.$Message.success(successMsg);
} else {
console.log(successMsg);
}
resolve(true);
} else {
throw new Error('Copy command was unsuccessful');
}
} catch (err) {
console.error('复制失败:', err);
if (vm && vm.$Message) {
vm.$Message.error(errorMsg);
} else {
console.error(errorMsg);
}
resolve(false);
} finally {
document.body.removeChild(textarea);
}
});
}
/**
* @param {string} text 要复制的文本
* @param {Object} options 配置选项
* @returns {Promise<boolean>} 是否复制成功
*/
export async function modernCopyToClipboard(text, options = {}) {
const {
successMsg = '复制成功',
errorMsg = '复制失败,请手动复制',
vm = null
} = options;
if (navigator.clipboard && window.isSecureContext) {
await navigator?.clipboard?.writeText(text);
if (vm && vm.$Message) {
vm.$Message.success(successMsg);
} else {
console.log(errorMsg);
}
} else {
return copyToClipboard(text, options);
}
}
export default modernCopyToClipboard;

32
packages/utils/common.js

@ -0,0 +1,32 @@
// 设置页面元素对应高亮
export function setHighActive(dom) {
const ele = document.getElementById(dom)
ele.classList.add('ceshi')
ele.scrollIntoView({behavior:'smooth',block:'start'})
setTimeout(()=>{
ele.classList.remove('ceshi')
},1000)
}
export function getServicePriceDesc(price, price_unit, unit_num) {
let unit = 0;
let unit_str = "";
if (unit_num == 1) return price + price_unit +'/篇';
if (unit_num/10000 < 10) {
unit = Math.ceil(unit_num/10000);
unit_str = unit == 1 ? '万' : unit+'万';
}
if (unit_num/1000 < 10) {
unit = Math.ceil(unit_num/1000);
unit_str = unit == 1 ? '千' : unit+'千';
}
if (unit_num/100 < 10) {
unit = Math.ceil(unit_num/100);
unit_str = unit == 1 ? '百' : unit+'百';
}
return price + price_unit + "/" +unit_str + "字符";
}

19
packages/utils/dirClipBoard.js

@ -0,0 +1,19 @@
import modernCopyToClipboard from '@/utils/clipboard';
export default {
install(Vue) {
Vue.directive('clipboard', {
bind(el, binding) {
el.style.cursor = 'pointer';
el.addEventListener('click', async () => {
const text = binding.value || el.innerText;
const options = {
vm: binding.instance,
...(binding.arg || {})
};
await modernCopyToClipboard(text, options);
});
}
});
}
};

11
packages/utils/eventBus.js

@ -0,0 +1,11 @@
import Vue from 'vue'
// 创建全局事件总线
const EventBus = new Vue()
// 封装常用方法
export const $on = EventBus.$on.bind(EventBus)
export const $once = EventBus.$once.bind(EventBus)
export const $off = EventBus.$off.bind(EventBus)
export const $emit = EventBus.$emit.bind(EventBus)
export default EventBus

17
packages/utils/headerIcon.js

@ -0,0 +1,17 @@
export default {
methods: {
renderHeaderWithIcon(h, { column }, iconPath) {
return h('div', [
column.label,
h('img', {
attrs: { src: iconPath },
style: {
width: '10px',
height: '10px',
marginLeft: '3px',
}
})
])
}
}
}

93
packages/utils/request.js

@ -0,0 +1,93 @@
// src/utils/request.js
import axios from "axios";
// 创建 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // 从环境变量中读取 API 基础地址
timeout: 60000, // 请求超时时间
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
// 在发送请求之前做一些处理,例如添加 token
const token = localStorage.getItem("token");
if (token) {
config.headers["Auth"] = `${token}`;
}
return config;
},
(error) => {
// 对请求错误做些什么
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
(response) => {
// 对响应数据做一些处理
const res = response.data;
if (!res.status) {
// 如果返回的 status 不是 true,则视为错误
// return Promise.reject(new Error(res.info || "请求失败"));
}
return res;
},
(error) => {
// 对响应错误做些什么
if (error.response) {
switch (error.response.status) {
case 401:
// 未授权,跳转到登录页
window.location.href = "/login";
break;
case 404:
// 资源未找到
console.error("资源未找到");
break;
case 500:
// 服务器错误
console.error("服务器错误");
break;
default:
console.error("请求失败", error.message);
}
}
return Promise.reject(error);
}
);
/**
* 封装请求方法
* @param {string} method 请求方法 (GET, POST, PUT, DELETE )
* @param {string} url 请求地址
* @param {object} data 请求参数
* @param {object} config 其他 axios 配置
* @returns {Promise} 返回请求结果
*/
const request = (method, url, data = {}, config = {}) => {
const lowerCaseMethod = method.toLowerCase();
if (lowerCaseMethod === "get") {
// GET 请求将参数拼接到 URL 上
return service({
method: "get",
url,
params: data,
...config,
});
} else {
// 其他请求(POST, PUT, DELETE 等)将参数放在请求体中
return service({
method: lowerCaseMethod,
url,
data,
...config,
});
}
};
export default request;
Loading…
Cancel
Save