Commit 33db8e9fb966997a6f1c5581f367afce65fe5066

Authored by ly525
1 parent acd59990

feat: pick image from image gallery

front-end/h5/src/components/core/styles/index.scss
@@ -172,6 +172,11 @@ @@ -172,6 +172,11 @@
172 justify-content: center; 172 justify-content: center;
173 } 173 }
174 174
  175 +.flex-space-between {
  176 + display: flex !important;
  177 + justify-content: space-between;
  178 +}
  179 +
175 .cursor-pointer { 180 .cursor-pointer {
176 cursor: pointer !important; 181 cursor: pointer !important;
177 } 182 }
178 \ No newline at end of file 183 \ No newline at end of file
front-end/h5/src/components/core/support/image-gallery/components/image-item.js 0 → 100644
  1 +export default {
  2 + props: {
  3 + item: {
  4 + type: Object,
  5 + default: () => ({})
  6 + },
  7 + height: {
  8 + type: Number,
  9 + default: 142
  10 + }
  11 + },
  12 + render (h) {
  13 + if (this.item.loading) {
  14 + return <a-spin>
  15 + <a-card hoverable>
  16 + <div
  17 + slot="cover"
  18 + style={{
  19 + height: `${this.height}px`
  20 + }}>
  21 + </div>
  22 + </a-card>
  23 + </a-spin>
  24 + }
  25 + return (
  26 + <a-card
  27 + hoverable
  28 + >
  29 + <div
  30 + slot="cover"
  31 + style={{
  32 + backgroundImage: `url(${this.item.previewURL})`,
  33 + backgroundSize: 'cover',
  34 + height: `${this.height}px`
  35 + }}>
  36 + </div>
  37 + </a-card>
  38 + )
  39 + }
  40 +}
front-end/h5/src/components/core/support/image-gallery/components/uploader.js 0 → 100644
  1 +export default {
  2 + props: {
  3 + visible: {
  4 + type: Boolean,
  5 + default: false
  6 + },
  7 + handleClose: {
  8 + type: Function,
  9 + default: () => {}
  10 + },
  11 + uploadSuccess: {
  12 + type: Function,
  13 + default: () => {}
  14 + },
  15 + beforeUpload: {
  16 + type: Function,
  17 + default: (file) => file
  18 + }
  19 + },
  20 + computed: {
  21 + },
  22 + data: () => ({
  23 + loading: false
  24 + }),
  25 + methods: {
  26 + handleBeforeUpload (file) {
  27 + return this.beforeUpload(file)
  28 + },
  29 + handleChange (info) {
  30 + this.loading = true
  31 + const status = info.file.status
  32 + if (status !== 'uploading') {
  33 + console.log(info.file, info.fileList)
  34 + }
  35 + if (status === 'done') {
  36 + this.loading = false
  37 + this.uploadSuccess(info)
  38 + this.$message.success(`${info.file.name} file uploaded successfully.`)
  39 + } else if (status === 'error') {
  40 + this.$message.error(`${info.file.name} file upload failed.`)
  41 + }
  42 + }
  43 + },
  44 + render (h) {
  45 + return (
  46 + <a-upload
  47 + name="files"
  48 + action="/upload"
  49 + beforeUpload={this.handleBeforeUpload}
  50 + onChange={this.handleChange}>
  51 + <slot>
  52 + <a-button>
  53 + <a-icon type="upload" /> Click to Upload
  54 + </a-button>
  55 + </slot>
  56 + </a-upload>
  57 + )
  58 + },
  59 + mounted () {
  60 + }
  61 +}
front-end/h5/src/components/core/support/image-gallery/gallery.js 0 → 100644
  1 +import './gallery.scss'
  2 +import PersonalTab from './tabs/personal.js'
  3 +import PixabayTab from './tabs/pixabay.js'
  4 +
  5 +export default {
  6 + components: {
  7 + },
  8 + props: {
  9 + visible: {
  10 + type: Boolean,
  11 + default: false
  12 + },
  13 + value: {
  14 + type: String,
  15 + default: ''
  16 + }
  17 + },
  18 + data: () => ({
  19 + tabs: [
  20 + {
  21 + value: 'personal',
  22 + label: '我的图库'
  23 + },
  24 + {
  25 + value: 'pixabay',
  26 + label: 'Pixabay图库'
  27 + }
  28 + ],
  29 + activeTab: 'personal',
  30 + innerVisible: false,
  31 + pixabayList: []
  32 + }),
  33 + computed: {
  34 + },
  35 + watch: {
  36 + visible (value) {
  37 + this.innerVisible = value
  38 + }
  39 + },
  40 + methods: {
  41 + handleClose () {
  42 + this.innerVisible = false
  43 + },
  44 + changeTab ({ key }) {
  45 + this.activeTab = key
  46 + },
  47 + handleSelectImage (item) {
  48 + this.handleClose()
  49 + this.$emit('change', item.previewURL)
  50 + },
  51 + renderContent () {
  52 + switch (this.activeTab) {
  53 + case 'personal':
  54 + return <PersonalTab onChangeItem={item => {
  55 + this.handleSelectImage(item)
  56 + }}/>
  57 + case 'pixabay':
  58 + return <PixabayTab onChange={item => {
  59 + this.handleSelectImage(item)
  60 + }}/>
  61 + }
  62 + },
  63 + renderDefaultActivator () {
  64 + const activatorWithoutImg = (
  65 + <div
  66 + class="default-activator cursor-pointer "
  67 + onClick={() => { this.innerVisible = true }}
  68 + >
  69 + <a-icon type="plus" />
  70 + </div>
  71 + )
  72 +
  73 + const activatorWithImg = (
  74 + <div
  75 + class="default-activator cursor-pointer "
  76 + onClick={() => { this.innerVisible = true }}
  77 + >
  78 + <img src={this.value} style={{ width: '100%' }} />
  79 + <div class="flex-space-between" style="margin-top: 8px;">
  80 + <a-button>更换图片</a-button>
  81 + <a-button onClick={e => {
  82 + e.stopPropagation()
  83 + }}>裁剪图片</a-button>
  84 + </div>
  85 + </div>
  86 + )
  87 + return (this.value ? activatorWithImg : activatorWithoutImg)
  88 + }
  89 + },
  90 + render (h) {
  91 + return (
  92 + <div>
  93 + <slot>{this.renderDefaultActivator()}</slot>
  94 + <a-modal
  95 + closable
  96 + title="图片库"
  97 + width="65%"
  98 + visible={this.innerVisible}
  99 + onOk={this.handleClose}
  100 + onCancel={this.handleClose}
  101 + bodyStyle={{ margin: 0, padding: 0 }}
  102 + >
  103 + <a-layout style="height: 500px; position: relative;">
  104 + <a-layout-sider width="200px" style="background-color: white;">
  105 + <a-menu mode="inline" defaultSelectedKeys={['personal']} onClick={this.changeTab}>
  106 + {
  107 + this.tabs.map((tab, index) => (
  108 + <a-menu-item key={tab.value} >
  109 + <a-icon type="user" />
  110 + <span>{tab.label}</span>
  111 + </a-menu-item>
  112 + ))
  113 + }
  114 + </a-menu>
  115 + </a-layout-sider>
  116 + <a-layout-content>
  117 + {this.renderContent()}
  118 + </a-layout-content>
  119 + </a-layout>
  120 + </a-modal>
  121 + </div>
  122 + )
  123 + }
  124 +}
front-end/h5/src/components/core/support/image-gallery/gallery.scss 0 → 100644
  1 +.default-activator {
  2 + border: 1px dashed #eee;
  3 + text-align: center;
  4 +}
0 \ No newline at end of file 5 \ No newline at end of file
front-end/h5/src/components/core/support/image-gallery/tabs/personal.js 0 → 100644
  1 +import axios from 'axios'
  2 +import ImageItem from '../components/image-item.js'
  3 +import Uploader from '../components/uploader.js'
  4 +
  5 +export default {
  6 + data: () => ({
  7 + items: [],
  8 + cachedItems: [],
  9 + loading: false
  10 + }),
  11 + methods: {
  12 + uploadSuccess ({ file, fileList }) {
  13 + const response = file.response.length && file.response[0]
  14 + this.items = [{ name: response.name, previewURL: response.url }, ...this.cachedItems]
  15 + },
  16 + beforeUpload (file) {
  17 + this.items.unshift({
  18 + loading: true
  19 + })
  20 + return file
  21 + }
  22 + },
  23 + render (h) {
  24 + return (
  25 + <div>
  26 + <a-spin tip="Loading..." spinning={this.loading}>
  27 + <a-card>
  28 + <Uploader
  29 + slot="extra"
  30 + beforeUpload={file => this.beforeUpload(file)}
  31 + uploadSuccess={info => this.uploadSuccess(info)}
  32 + />
  33 + <a-list
  34 + style="height: 400px; overflow: auto;"
  35 + grid={{ gutter: 12, column: 3 }}
  36 + dataSource={this.items}
  37 + renderItem={(item, index) => (
  38 + <a-list-item onClick={() => {
  39 + debugger
  40 + this.$emit('changeItem', item)
  41 + }}>
  42 + <ImageItem item={item} />
  43 + </a-list-item>
  44 + )}
  45 + >
  46 + </a-list>
  47 + </a-card>
  48 + </a-spin>
  49 + </div>
  50 + )
  51 + },
  52 + mounted () {
  53 + // demo code
  54 + axios
  55 + .get('https://pixabay.com/api/?key=12120348-2ad26e4cc05d9bc068097ab3b&q=yellow+flowers&image_type=photo&pretty=true')
  56 + .then(res => {
  57 + this.items = res.data.hits
  58 + this.cachedItems = res.data.hits.slice(0)
  59 + })
  60 + }
  61 +}
front-end/h5/src/components/core/support/image-gallery/tabs/pixabay.js 0 → 100644
  1 +import axios from 'axios'
  2 +import ImageItem from '../components/image-item.js'
  3 +
  4 +export default {
  5 + data: () => ({
  6 + items: [],
  7 + loading: false,
  8 + options: {
  9 + key: '12120348-2ad26e4cc05d9bc068097ab3b', // pixabay demo key from https://pixabay.com/zh/service/about/api/
  10 + image_type: 'photo',
  11 + pretty: true,
  12 + q: 'yellow+flowers',
  13 + orientation: 'all' // "all", "horizontal", "vertical"
  14 + }
  15 + }),
  16 + computed: {
  17 + isVertial () {
  18 + return this.options.orientation === 'vertical'
  19 + }
  20 + },
  21 + methods: {
  22 + queryAPI () {
  23 + axios
  24 + .get('https://pixabay.com/api/', { params: this.options })
  25 + .then(res => {
  26 + this.items = res.data.hits
  27 + })
  28 + }
  29 + },
  30 + render (h) {
  31 + return (
  32 + <div>
  33 + <a-spin tip="Loading..." spinning={this.loading}>
  34 + <a-card >
  35 + <div slot="extra" style={{ display: 'flex' }}>
  36 + <a-dropdown>
  37 + <a-menu slot="overlay" onClick={({ key }) => {
  38 + this.options.orientation = key
  39 + this.queryAPI()
  40 + }}>
  41 + <a-menu-item key="all"><a-icon type="user" />任意方位</a-menu-item>
  42 + <a-menu-item key="horizontal"><a-icon type="user" />水平</a-menu-item>
  43 + <a-menu-item key="vertical"><a-icon type="user" />竖直</a-menu-item>
  44 + </a-menu>
  45 + <a-button style="margin-left: 8px" type="link">
  46 + 图片方向 <a-icon type="down" />
  47 + </a-button>
  48 + </a-dropdown>
  49 + <a-input-search
  50 + placeholder="input search text"
  51 + onSearch={value => {
  52 + this.options.q = value
  53 + this.queryAPI()
  54 + }}
  55 + />
  56 + </div>
  57 + <a-list
  58 + grid={{ gutter: 12, column: this.isVertial ? 4 : 3 }}
  59 + dataSource={this.items}
  60 + renderItem={(item, index) => (
  61 + <a-list-item onClick={item => {
  62 + this.$emit('changeItem', item)
  63 + }}>
  64 + <ImageItem item={item} height={this.isVertial ? 240 : 142 } />
  65 + </a-list-item>
  66 + )}
  67 + >
  68 + </a-list>
  69 + </a-card>
  70 + </a-spin>
  71 + </div>
  72 + )
  73 + },
  74 + mounted () {
  75 + this.queryAPI()
  76 + }
  77 +}
front-end/h5/src/components/plugins/lbp-background.js
  1 +import ImageGallery from '@/components/core/support/image-gallery/gallery.js'
  2 +
1 export default { 3 export default {
2 name: 'lbp-background', 4 name: 'lbp-background',
3 render () { 5 render () {
@@ -41,8 +43,8 @@ export default { @@ -41,8 +43,8 @@ export default {
41 editorConfig: { 43 editorConfig: {
42 propsConfig: { 44 propsConfig: {
43 imgSrc: { 45 imgSrc: {
44 - // type: 'picture-picker',  
45 - type: 'a-input', 46 + type: 'image-gallery',
  47 + // type: 'a-input',
46 label: '图片url', 48 label: '图片url',
47 prop: { 49 prop: {
48 type: 'textarea' 50 type: 'textarea'
@@ -60,7 +62,7 @@ export default { @@ -60,7 +62,7 @@ export default {
60 } 62 }
61 }, 63 },
62 components: { 64 components: {
63 - // 'picture-picker': PicturePicker, 65 + 'image-gallery': ImageGallery
64 } 66 }
65 } 67 }
66 } 68 }